From 3279c45927dfe8be53149c48f40e4fd126036414 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Tue, 22 Apr 2025 11:45:20 +0200 Subject: [PATCH 01/12] patched reporters and optimised applyTrotter See PR #589 for info on each patch --- .github/workflows/audit.yml | 2 ++ .github/workflows/compile.yml | 2 ++ .github/workflows/doc.yml | 2 +- .github/workflows/test_free.yml | 2 ++ .github/workflows/test_paid.yml | 2 +- quest/src/api/operations.cpp | 25 ++++++++++++++++++------- quest/src/core/printer.cpp | 19 ++++++++++++++----- quest/src/core/printer.hpp | 10 +++++++++- quest/src/core/validation.cpp | 7 +++++-- 9 files changed, 54 insertions(+), 17 deletions(-) diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 041affc12..f6cbb5e22 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -14,9 +14,11 @@ on: push: branches: - main + - devel pull_request: branches: - main + - devel jobs: diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index fa3360cfa..4d99caa4d 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -20,9 +20,11 @@ on: push: branches: - main + - devel pull_request: branches: - main + - devel jobs: diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 8cdc9d832..7be795273 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -15,7 +15,7 @@ permissions: on: push: branches: - - master + - main workflow_dispatch: diff --git a/.github/workflows/test_free.yml b/.github/workflows/test_free.yml index a94894cef..3d3aace47 100644 --- a/.github/workflows/test_free.yml +++ b/.github/workflows/test_free.yml @@ -14,9 +14,11 @@ on: push: branches: - main + - devel pull_request: branches: - main + - devel jobs: diff --git a/.github/workflows/test_paid.yml b/.github/workflows/test_paid.yml index ec25233f5..878336f7f 100644 --- a/.github/workflows/test_paid.yml +++ b/.github/workflows/test_paid.yml @@ -19,7 +19,7 @@ name: test (paid, accelerated) # @todo # this workflow can only be run on the 'default' -# branch (i.e. master) when manually triggered by +# branch (i.e. main) when manually triggered by # github actions, so as not to incur unexpected # costs. I want for this to be automatically # enqueued but not run in a PR, requiring manual diff --git a/quest/src/api/operations.cpp b/quest/src/api/operations.cpp index 923c16b01..01d562542 100644 --- a/quest/src/api/operations.cpp +++ b/quest/src/api/operations.cpp @@ -1135,8 +1135,8 @@ void applyFirstOrderTrotter(Qureg qureg, PauliStrSum sum, qreal angle, bool reve for (qindex i=0; i(complex num); template string printer_toStr(complex num); +// explicit qreal overload so that real sig-figs can be changed +string printer_toStr(qreal num) { + + // uses user-set significant figures + return floatToStr(num); +} + + // alias as toStr() just for internal brevity // (this seems backward; ordinarily we would define toStr() as // the templated inner-function and define concretely-typed public @@ -776,11 +784,12 @@ MatrixQuadrantInds getTruncatedMatrixQuadrantInds(qindex numRows, qindex numCols MatrixQuadrantInds inds; - // according to the user-set truncations - qindex maxNumLeftCols = global_maxNumPrintedCols / 2; // floors - qindex maxNumRightCols = global_maxNumPrintedCols - maxNumLeftCols; - qindex maxNumUpperRows = global_maxNumPrintedRows / 2; // floors - qindex maxNumLowerRows = global_maxNumPrintedRows - maxNumUpperRows; + // find maximum size of matrix quadrants according to user-truncatins. + // Choose right & lower first so that When num=odd, extra left & upper elem is shown + qindex maxNumRightCols = global_maxNumPrintedCols / 2; // floors + qindex maxNumLeftCols = global_maxNumPrintedCols - maxNumRightCols; + qindex maxNumLowerRows = global_maxNumPrintedRows / 2; // floors + qindex maxNumUpperRows = global_maxNumPrintedRows - maxNumLowerRows; // may be ignored (and will unimportantly underflow when not truncating) inds.rightStartCol = numCols - maxNumRightCols; diff --git a/quest/src/core/printer.hpp b/quest/src/core/printer.hpp index 003f6a5b9..3b218fb67 100644 --- a/quest/src/core/printer.hpp +++ b/quest/src/core/printer.hpp @@ -21,6 +21,8 @@ #include #include +// beware that files including this header receive all these +// namespace items; a worthwhile evil to keep this readable using std::tuple; using std::string; using std::vector; @@ -70,12 +72,18 @@ template string printer_toStr(T expr) { // write to buffer (rather than use to_string()) so that floating-point numbers - // are automatically converted to scientific notation when necessary + // are automatically converted to scientific notation when necessary. Beware + // that the user configured significant figures are not reflected here. + std::ostringstream buffer; buffer << expr; return buffer.str(); } +// explicit qreal version of above, affected by user-set significant figures +string printer_toStr(qreal num); + + /* * SUBSTRING PREPARATION diff --git a/quest/src/core/validation.cpp b/quest/src/core/validation.cpp index 7da81760c..f1c123ca4 100644 --- a/quest/src/core/validation.cpp +++ b/quest/src/core/validation.cpp @@ -1066,8 +1066,11 @@ namespace report { void default_inputErrorHandler(const char* func, const char* msg) { - // safe to call even before MPI has been setup, and ignores user-set trailing newlines - print(string("") + // safe to call even before MPI has been setup, and ignores user-set trailing newlines. + // It begins with \n to interrupt half-printed lines (when trailing newlines are set to + // 0 via setNumReportedNewlines(0)), for visual clarity. Note that user's overriding + // functions might not think to print an initial newline but oh well! + print(string("\n") + "QuEST encountered a validation error during function " + "'" + func + "':\n" + msg + "\n" + "Exiting...\n"); From 2b4623c7eaada61b89080925acb1a950473f10b0 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Tue, 22 Apr 2025 16:35:27 +0200 Subject: [PATCH 02/12] added setReportedPauli(Chars|StrStyle) --- quest/include/debug.h | 32 +++++++++++ quest/src/api/debug.cpp | 16 ++++++ quest/src/api/paulis.cpp | 3 +- quest/src/core/printer.cpp | 99 ++++++++++++++++++++++++++++++++--- quest/src/core/printer.hpp | 4 ++ quest/src/core/validation.cpp | 21 ++++++++ quest/src/core/validation.hpp | 4 ++ tests/unit/debug.cpp | 3 ++ 8 files changed, 174 insertions(+), 8 deletions(-) diff --git a/quest/include/debug.h b/quest/include/debug.h index 5febafa46..fbe34e3e1 100644 --- a/quest/include/debug.h +++ b/quest/include/debug.h @@ -121,6 +121,38 @@ void setMaxNumReportedSigFigs(int numSigFigs); void setNumReportedNewlines(int numNewlines); +/** + * @notdoced + * @nottested + * @myexample + * ``` + PauliStr str = getInlinePauliStr("XYZ", {0,10,20}); + reportPauliStr(str); + + setReportedPauliChars(".xyz"); + reportPauliStr(str); + * ``` + */ +void setReportedPauliChars(const char* paulis); + + +/** + * @notdoced + * @nottested + * @myexample + * ``` + PauliStr str = getInlinePauliStr("XYZ", {0,10,20}); + + setReportedPauliStrStyle(0); + reportPauliStr(str); + + setReportedPauliStrStyle(1); + reportPauliStr(str); + * ``` + */ +void setReportedPauliStrStyle(int style); + + /** @} */ diff --git a/quest/src/api/debug.cpp b/quest/src/api/debug.cpp index 04efdf35b..4ff2c185d 100644 --- a/quest/src/api/debug.cpp +++ b/quest/src/api/debug.cpp @@ -155,6 +155,22 @@ void setNumReportedNewlines(int numNewlines) { } +void setReportedPauliChars(const char* paulis) { + validate_envIsInit(__func__); + validate_numPauliChars(paulis, __func__); + + printer_setPauliChars(paulis); +} + + +void setReportedPauliStrStyle(int flag) { + validate_envIsInit(__func__); + validate_reportedPauliStrStyleFlag(flag, __func__); + + printer_setPauliStrFormat(flag); +} + + /* * GPU CACHE diff --git a/quest/src/api/paulis.cpp b/quest/src/api/paulis.cpp index 967279e47..bbfa5bfde 100644 --- a/quest/src/api/paulis.cpp +++ b/quest/src/api/paulis.cpp @@ -327,7 +327,8 @@ PauliStr getPauliStr(int* paulis, int* indices, int numPaulis) { // validation ensures never causes stack overflow char pauliChars[MAX_NUM_PAULIS_PER_STR + 1]; // +1 for null-terminal - // made a char array from the pauli codes + // make a char array from the pauli codes, using an arbitrary + // choice of the Pauli characters accepted by the API (like IXYZ) for (int i=0; i=0; i--) - out += labels[paulis_getPauliAt(str, i)]; + for (int i=numPaulis-1; i>=0; i--) { + int code = paulis_getPauliAt(str, i); // 0123 + out += global_pauliChars[code]; // IXYZ unless user-overriden + } return out; } +string getPauliStrAsIndexString(PauliStr str, int numPaulis) { + + string out = ""; + + // prematurely optimise (hehe) by avoiding repeated allocations + // induced by below string concatenation, since we can bound the + // string length; each Pauli is 1 char, each index is max 2 digits + // (<64) and each inter-Pauli space is 1 char, so <=4 chars per Pauli. + int maxLen = numPaulis * 4; // <= 256 always + out.reserve(maxLen); + + for (int i=0; i= 1+paulis_getIndOfLefmostNonIdentityPauli + /// to ensure a bug never occludes a PauliStr. Very low priority! + + switch(global_pauliStrFormatFlag) { + case 0: return getPauliStrAsAllQubitsString(str, numPauliChars); + case 1: return getPauliStrAsIndexString(str, numPauliChars); + } + + /// @todo + /// to be defensively-designed, we should throw a runtime error + /// here because global_pauliStrFormatFlag was mutilated. This is + /// a very low priority; so we just return a suspicious string! + return "(PauliStr stringifying failed - please alert the QuEST devs)"; +} + + void print_elemsWithoutNewline(PauliStr str, string indent) { // only root node ever prints if (!comm_isRootNode()) return; - int numPaulis = 1 + paulis_getIndOfLefmostNonIdentityPauli(str); - cout << indent << getPauliStrAsString(str, numPaulis); + cout << indent << getPauliStrAsString(str); // beware that NO trailing newlines are printed so subsequent // calls (without calling print_newlines()) will run-on diff --git a/quest/src/core/printer.hpp b/quest/src/core/printer.hpp index 3b218fb67..d2ff8274d 100644 --- a/quest/src/core/printer.hpp +++ b/quest/src/core/printer.hpp @@ -42,6 +42,10 @@ void printer_setNumTrailingNewlines(int numNewlines); int printer_getNumTrailingNewlines(); +void printer_setPauliChars(string newChars); + +void printer_setPauliStrFormat(int flag); + /* diff --git a/quest/src/core/validation.cpp b/quest/src/core/validation.cpp index f1c123ca4..4d316cdff 100644 --- a/quest/src/core/validation.cpp +++ b/quest/src/core/validation.cpp @@ -134,6 +134,12 @@ namespace report { string INSUFFICIENT_NUM_REPORTED_NEWLINES = "The number of trailing newlines (set by setNumReportedNewlines()) is zero which is not permitted when calling multi-line reporters."; + string INVALID_NUM_NEW_PAULI_CHARS = + "Given an invalid number of Pauli characters. Must specify precisely four to respectively replace IXYZ."; + + string INVALID_REPORTED_PAULI_STR_STYLE_FLAG = + "Given an unrecognised style flag (${FLAG}). Legal flags are 0 and 1."; + /* * QUREG CREATION @@ -1433,6 +1439,21 @@ void validate_numReportedNewlinesAboveZero(const char* caller) { assertThat(printer_getNumTrailingNewlines() > 0, report::INSUFFICIENT_NUM_REPORTED_NEWLINES, caller); } +void validate_numPauliChars(const char* paulis, const char* caller) { + + // check position of terminal char, else default to numChars=5 (illegal) + int numChars = 0; + for (int i=0; i<5 && paulis[i] != '\0'; i++) + numChars++; + + assertThat(numChars==4, report::INVALID_NUM_NEW_PAULI_CHARS, caller); +} + +void validate_reportedPauliStrStyleFlag(int flag, const char* caller) { + + assertThat(flag==0 || flag==1, report::INVALID_REPORTED_PAULI_STR_STYLE_FLAG, {{"${FLAG}",flag}}, caller); +} + /* diff --git a/quest/src/core/validation.hpp b/quest/src/core/validation.hpp index dbfb5548d..2aa9da71a 100644 --- a/quest/src/core/validation.hpp +++ b/quest/src/core/validation.hpp @@ -103,6 +103,10 @@ void validate_newNumReportedNewlines(int numNewlines, const char* caller); void validate_numReportedNewlinesAboveZero(const char* caller); +void validate_numPauliChars(const char* paulis, const char* caller); + +void validate_reportedPauliStrStyleFlag(int flag, const char* caller); + /* diff --git a/tests/unit/debug.cpp b/tests/unit/debug.cpp index 092bb959f..bc20a0a56 100644 --- a/tests/unit/debug.cpp +++ b/tests/unit/debug.cpp @@ -750,3 +750,6 @@ void setMaxNumReportedItems(qindex numRows, qindex numCols); void getEnvironmentString(char str[200]); +void setReportedPauliChars(const char* paulis); + +void setReportedPauliStrStyle(int style); From 3699f7c46ca892a4c2145f78d61d441514cf9487 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 27 Apr 2025 14:40:55 +0200 Subject: [PATCH 03/12] restructured and extended examples (#593) - moved and renamed isolated examples - tidied example-related CMakeLists.txt - updated example-related doc - added dynamics example - updated min_example to be C/C++ agnostic - change compile workflow to run Windows first (since MSVC is the most pedantic compiler of those tested so should run and fail soonest) --- .github/workflows/compile.yml | 2 +- CMakeLists.txt | 2 +- README.md | 2 +- docs/cmake.md | 3 +- docs/compile.md | 76 ++++++- docs/launch.md | 72 ++++--- examples/CMakeLists.txt | 66 +++++- examples/debug/CMakeLists.txt | 41 ---- examples/extended/CMakeLists.txt | 3 + examples/extended/dynamics.c | 191 ++++++++++++++++++ examples/extended/dynamics.cpp | 185 +++++++++++++++++ examples/isolated/CMakeLists.txt | 3 + .../complex_arithmetic.c} | 0 .../complex_arithmetic.cpp} | 0 .../initialising_krausmaps.c} | 0 .../initialising_krausmaps.cpp} | 0 .../initialising_matrices.c} | 0 .../initialising_matrices.cpp} | 0 .../initialising_paulis.c} | 0 .../initialising_paulis.cpp} | 0 .../initialising_superoperators.c} | 0 .../initialising_superoperators.cpp} | 0 .../reporting_environments.c} | 0 .../reporting_environments.cpp} | 0 .../reporting_matrices.c} | 0 .../reporting_matrices.cpp} | 0 .../paulis.c => isolated/reporting_paulis.c} | 0 .../reporting_paulis.cpp} | 0 .../qureg.c => isolated/reporting_quregs.c} | 0 .../reporting_quregs.cpp} | 0 .../setting_errorhandler.c} | 0 .../setting_errorhandler.cpp} | 0 examples/krausmaps/CMakeLists.txt | 34 ---- examples/matrices/CMakeLists.txt | 34 ---- examples/numbers/CMakeLists.txt | 30 --- examples/paulis/CMakeLists.txt | 34 ---- examples/reporters/CMakeLists.txt | 130 ------------ examples/superoperators/CMakeLists.txt | 34 ---- .../{min_example.cpp => min_example.c} | 5 +- 39 files changed, 566 insertions(+), 381 deletions(-) delete mode 100644 examples/debug/CMakeLists.txt create mode 100644 examples/extended/CMakeLists.txt create mode 100644 examples/extended/dynamics.c create mode 100644 examples/extended/dynamics.cpp create mode 100644 examples/isolated/CMakeLists.txt rename examples/{numbers/arithmetic.c => isolated/complex_arithmetic.c} (100%) rename examples/{numbers/arithmetic.cpp => isolated/complex_arithmetic.cpp} (100%) rename examples/{krausmaps/initialisation.c => isolated/initialising_krausmaps.c} (100%) rename examples/{krausmaps/initialisation.cpp => isolated/initialising_krausmaps.cpp} (100%) rename examples/{matrices/initialisation.c => isolated/initialising_matrices.c} (100%) rename examples/{matrices/initialisation.cpp => isolated/initialising_matrices.cpp} (100%) rename examples/{paulis/initialisation.c => isolated/initialising_paulis.c} (100%) rename examples/{paulis/initialisation.cpp => isolated/initialising_paulis.cpp} (100%) rename examples/{superoperators/initialisation.c => isolated/initialising_superoperators.c} (100%) rename examples/{superoperators/initialisation.cpp => isolated/initialising_superoperators.cpp} (100%) rename examples/{reporters/env.c => isolated/reporting_environments.c} (100%) rename examples/{reporters/env.cpp => isolated/reporting_environments.cpp} (100%) rename examples/{reporters/matrices.c => isolated/reporting_matrices.c} (100%) rename examples/{reporters/matrices.cpp => isolated/reporting_matrices.cpp} (100%) rename examples/{reporters/paulis.c => isolated/reporting_paulis.c} (100%) rename examples/{reporters/paulis.cpp => isolated/reporting_paulis.cpp} (100%) rename examples/{reporters/qureg.c => isolated/reporting_quregs.c} (100%) rename examples/{reporters/qureg.cpp => isolated/reporting_quregs.cpp} (100%) rename examples/{debug/errorhandling.c => isolated/setting_errorhandler.c} (100%) rename examples/{debug/errorhandling.cpp => isolated/setting_errorhandler.cpp} (100%) delete mode 100644 examples/krausmaps/CMakeLists.txt delete mode 100644 examples/matrices/CMakeLists.txt delete mode 100644 examples/numbers/CMakeLists.txt delete mode 100644 examples/paulis/CMakeLists.txt delete mode 100644 examples/reporters/CMakeLists.txt delete mode 100644 examples/superoperators/CMakeLists.txt rename examples/tutorials/{min_example.cpp => min_example.c} (80%) diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 4d99caa4d..6754cc7b5 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -53,7 +53,7 @@ jobs: # compile QuEST with all combinations of below flags matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [windows-latest, ubuntu-latest, macos-latest] precision: [1, 2, 4] omp: [ON, OFF] mpi: [ON, OFF] diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e3392d41..b2b941c5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -428,7 +428,7 @@ add_subdirectory(quest) ## Examples add_executable(min_example - examples/tutorials/min_example.cpp + examples/tutorials/min_example.c ) target_link_libraries(min_example PRIVATE QuEST::QuEST) diff --git a/README.md b/README.md index cbc83593c..75c9f41f6 100644 --- a/README.md +++ b/README.md @@ -239,7 +239,7 @@ mkdir build cd build ``` -Compile the [minimum example](/examples/tutorials/min_example.cpp) using [cmake](https://cmake.org/): +Compile the [minimum example](/examples/tutorials/min_example.c) using [cmake](https://cmake.org/): ```bash cmake .. make diff --git a/docs/cmake.md b/docs/cmake.md index e0594f202..5007553e3 100644 --- a/docs/cmake.md +++ b/docs/cmake.md @@ -71,4 +71,5 @@ make | `CMAKE_C_COMPILER` | The C compiler that will be used to compile QuEST. | [CMAKE_\_COMPILER](https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER.html) | | `CMAKE_INSTALL_PREFIX` | The directory to which QuEST will be installed when `make install` is invoked. A standard GNU directory structure (lib, bin, include) will be used inside the prefix directory. | [CMAKE_INSTALL_PREFIX](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html)
[GNUInstallDirs](https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html) | | `CMAKE_CUDA_ARCHITECTURES` | Used to set the value of `arch` when compiling for NVIDIA GPU. This is also known as the target GPU's "compute capability" and can be discovered [here](https://developer.nvidia.com/cuda-gpus). | [CMAKE_CUDA_ARCHITECTURES](https://cmake.org/cmake/help/latest/variable/CMAKE_CUDA_ARCHITECTURES.html) | -| `CMAKE_HIP_ARCHITECTURES` | Used to set the HIP platform which QuEST is compiled for when compiling for AMD GPU. | [CMAKE_HIP_ARCHITECTURES](https://cmake.org/cmake/help/latest/variable/CMAKE_HIP_ARCHITECTURES.html) | \ No newline at end of file +| `CMAKE_HIP_ARCHITECTURES` | Used to set the HIP platform which QuEST is compiled for when compiling for AMD GPU. | [CMAKE_HIP_ARCHITECTURES](https://cmake.org/cmake/help/latest/variable/CMAKE_HIP_ARCHITECTURES.html) | +| `CMAKE_RUNTIME_OUTPUT_DIRECTORY` | The output directory to which to save compiled executables, overriding the default `build` folder | [`CMAKE_RUNTIME_OUTPUT_DIRECTORY`](https://cmake.org/cmake/help/latest/variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY.html). | diff --git a/docs/compile.md b/docs/compile.md index b4a26a021..37fc6ad23 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -30,6 +30,7 @@ Compiling is configured with variables supplied by the [`-D` flag](https://cmake > - Optimising > - Linking > - Configuring +> * Location > * Precision > * Compilers > * Flags @@ -86,7 +87,7 @@ cmake --build . > cmake --build . --parallel > ``` -With no additional arguments, these commands compile [`min_example.cpp`](/examples/tutorials/min_example.cpp) into an executable `min_example` in the `build` folder which can be run via +With no additional arguments, these commands compile [`min_example.c`](/examples/tutorials/min_example.c) into an executable `min_example` in the `build` folder which can be run via ```bash ./min_example ``` @@ -188,6 +189,11 @@ where - `myfile.c` is your `C` source file (or `myfile.cpp` if using `C++`). - `myexec` is the output executable name, which will be saved in `build`. + +> [!IMPORTANT] +> `USER_SOURCE` can be any relative or absolute path to a file, but `OUTPUT_EXE` must be strictly a filename and cannot contain subdirectories. See Location to change the output directory. + + To compile multiple dependent files, such as ```cpp /* myfile.cpp */ @@ -241,6 +247,60 @@ to your project as a library! ## Configuring + + + + +### Location + +The location of your compiled executable(s) can be changed (from the default `build`) using [`CMAKE_RUNTIME_OUTPUT_DIRECTORY`](https://cmake.org/cmake/help/latest/variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY.html). +For example +```bash +# configure +cmake .. -D CMAKE_RUNTIME_OUTPUT_DIRECTORY=/full/path/to/output/dir/ +``` + +This applies to _all_ built executables, including your own custom files, the examples, and the unit tests. All executables will be at the top-level of the specified directory, and will _not_ be contained with subdirectories like `/examples/`. + +> [!TIP] +> Paths containing spaces can be individually escaped, or the path surrounded with quotations, i.e. +> ```bash +> cmake .. -D CMAKE_RUNTIME_OUTPUT_DIRECTORY="/full/path/to/output/dir/" +> ``` +> Beware that syntax like `~` will not be expanded inside quotation marks, but one can safely use alternative methods like +> ```bash +> "$HOME/path/from/home/to/output/dir/" +> "../../path/from/two/layers/above/to/output/dir/" +> ``` + +> [!NOTE] +> Building will fail if the linker has insufficient permissions to make a new directory, for example with message: +> ```bash +> ld: open() failed, errno=2 +> ``` +> This is remedied by ensuring the output directory already exists. +> ```bash +> # make directory +> export OUT_DIR=/full/path/to/output/dir/ +> mkdir $OUT_DIR +> +> # configure +> cmake .. -D CMAKE_RUNTIME_OUTPUT_DIRECTORY=$OUT_DIR +> +> # build +> cmake --build . +> ``` + +> [!IMPORTANT] +> Configuration will fail if any two executables have the same output name since they will not be separated into subdirectories and will collide. We do not gaurantee that all test and example filenames will remain unique in the future, such that use of `CMAKE_RUNTIME_OUTPUT_DIRECTORY` may become invalid except when also specifying +> ``` +> -D ENABLE_TESTING=OFF -D BUILD_EXAMPLES=OFF +> ``` + + + + + @@ -335,13 +395,21 @@ cmake .. -D BUILD_EXAMPLES=ON # build cmake --build . ``` -The executables will be saved in the (current) `build` directory, in a sub-directory structure mimicking the [`examples/`](/examples/) folder. They can be run by e.g. +Unless overridden with [`CMAKE_RUNTIME_OUTPUT_DIRECTORY`](https://cmake.org/cmake/help/latest/variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY.html), the executables will be saved in the `build` directory, in a sub-directory structure mimicking that of the [`examples/`](/examples/) folder. They can be run by e.g. ```bash -./examples/matrices/cpp_initialisation +./examples/isolated/initialising_paulis_c ``` -as elaborated upon in [`launch.md`](launch.md#tests). +as elaborated upon in [`launch.md`](launch.md#examples). +> [!NOTE] +> +> As [above](compile.md#compile_optimising), Windows users should specify additional build parameter `--config Release` which will cause the executables to be contained in an additional final `\Release\` subdirectory. Executables are also suffixed with `.exe`, e.g. +> ``` +> \examples\isolated\Release\initialising_paulis_c.exe +> ``` + + ------------------ diff --git a/docs/launch.md b/docs/launch.md index 447e0ff01..0053e0160 100644 --- a/docs/launch.md +++ b/docs/launch.md @@ -59,41 +59,57 @@ Launching your [compiled](compile.md) QuEST application can be as straightforwar > See [`compile.md`](compile.md#examples) for instructions on compiling the examples. -The example source codes are located in [`examples/`](/examples/) and are divided into subdirectories, e.g. + +The example source codes are located in [`examples/`](/examples/) with structure ``` examples/ - krausmaps/ - initialisation.c - initialisation.cpp - reporters/ - env.c - env.cpp - matrices.c - matrices.cpp - ... -``` -where `file.c` and `file.cpp` respectively demonstrate QuEST's `C11` and `C++14` interfaces. -These files are [compiled](compile.md#examples) into executables of the same name, respectively prefixed with `c_` or `cpp_`, and saved in subdirectories of `build` which mimic the structure of `examples/`. E.g. + isolated/ + complex_arithmetic.c + complex_arithmetic.cpp + ... + extended/ + dynamics.c + dynamics.cpp + ... + tutorials/ + min_example.c + ... +``` +where `file.c` and `file.cpp` respectively demo QuEST's `C11` and `C++14` interfaces. Files are divided between subdirectories: + - `isolated/` which contains demos of _one_ function or task, typically showcasing all the different syntaxes and interfaces available. + - `extended/` which contains longer, standalone examples performing common tasks and algorithms in quantum computing. + - `tutorials/` which contains guides with step-by-step explanations. + + +These files are [compiled](compile.md#examples) into executables of the same name, respectively suffixed with `_c` or `_cpp`, and (by default) are saved in subdirectories of `build` which mimic the structure of `examples/`. E.g. + ``` build/ examples/ - krausmaps/ - c_initialisation - cpp_initialisation - reporters/ - c_env - cpp_env - c_matrices - cpp_matrices - ... -``` + isolated/ + complex_arithmetic_c + complex_arithmetic_cpp + ... + extended/ + dynamics_c + dynamics_cpp + ... + tutorials/ + min_example_c +``` + +> [!NOTE] +> +> On Windows, the executables are located in `\Release\` subdirectories, assuming the parameter +> `--config Release` was specified during compilation (see [compiled](compile.md#compile_optimising)). + Most of these executables can be run directly from within `build`, e.g. ```bash -./examples/reporters/cpp_paulis +./examples/extended/dynamics_c ``` while others require command-line arguments: ```bash -./examples/reporters/c_env +./examples/extended/reporting_environments_cpp # output Must pass single cmd-line argument: @@ -105,6 +121,12 @@ Must pass single cmd-line argument: 6 = auto ``` +> [!NOTE] +> On Windows, the executables are `.exe` files and can be run with e.g. +> ``` +> \examples\isolated\Release\initialising_paulis_c.exe +> ``` + --------------------- diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index a3a7ab038..2498c710c 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,9 +1,61 @@ # @author Oliver Thomson Brown +# @author Erich Essmann (updating rpath) +# @author Tyson Jones (refactored to functions + glob) -add_subdirectory(krausmaps) -add_subdirectory(matrices) -add_subdirectory(numbers) -add_subdirectory(paulis) -add_subdirectory(reporters) -add_subdirectory(superoperators) -add_subdirectory(debug) + + +# compiles in_fn to ../examples/direc/in_fn_c + +function(add_example direc in_fn) + + # fn.cpp -> filename=fn, filelang=cpp + get_filename_component(filename ${in_fn} NAME_WE) + get_filename_component(filelang ${in_fn} LAST_EXT) + string(REPLACE "." "" filelang ${filelang}) + + set(target "${filename}_${filelang}") + set(out_fn "${filename}_${filelang}") + set(out_dir "${CMAKE_INSTALL_BINDIR}/examples/${direc}/") + + add_executable(${target} ${in_fn}) + target_link_libraries(${target} PUBLIC QuEST) + + install( + TARGETS ${target} + RUNTIME + DESTINATION ${out_dir} + ) + + set_target_properties(${target} + PROPERTIES + INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" + OUTPUT_NAME "${out_fn}" + ) + +endfunction() + + + +# compiles all .c or .cpp files in the subdirecs below + +function(add_all_local_examples) + + get_filename_component(direc ${CMAKE_CURRENT_LIST_DIR} NAME) + + file(GLOB files + "${CMAKE_CURRENT_SOURCE_DIR}/*.c" + "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" + ) + + foreach(fn ${files}) + add_example(${direc} ${fn}) + endforeach() + +endfunction() + + + +# all subdirecs below will invoke add_all_local_examples() + +add_subdirectory(isolated) +add_subdirectory(extended) diff --git a/examples/debug/CMakeLists.txt b/examples/debug/CMakeLists.txt deleted file mode 100644 index 9a60c2c91..000000000 --- a/examples/debug/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -# @author Tyson Jones (by duplicating files from...) -# @author Oliver Brown -# @author Erich Essmann - - -# C example - -add_executable(debug_c_errorhandling - errorhandling.c -) - -target_link_libraries(debug_c_errorhandling PUBLIC QuEST) - -install(TARGETS debug_c_errorhandling - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/debug -) -set_target_properties(debug_c_errorhandling - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME "c_errorhandling" -) - - -# C++ example - -add_executable(debug_cpp_errorhandling - errorhandling.cpp -) - -target_link_libraries(debug_cpp_errorhandling PUBLIC QuEST) - -install(TARGETS debug_cpp_errorhandling - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/debug -) -set_target_properties(debug_cpp_errorhandling - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME "cpp_errorhandling" -) diff --git a/examples/extended/CMakeLists.txt b/examples/extended/CMakeLists.txt new file mode 100644 index 000000000..5880c2ac0 --- /dev/null +++ b/examples/extended/CMakeLists.txt @@ -0,0 +1,3 @@ +# @author Tyson Jones + +add_all_local_examples() diff --git a/examples/extended/dynamics.c b/examples/extended/dynamics.c new file mode 100644 index 000000000..dd5ae00a7 --- /dev/null +++ b/examples/extended/dynamics.c @@ -0,0 +1,191 @@ +#include "quest.h" +#include +#include + + + +/* + * Prepare a Hamiltonian H under which dyanmical + * evolution will be simulated via Trotterisation + * of unitary-time evolution operator e^(-itH). + * If the Hamiltonian was fixed/known in advance, + * we could instead use createInlinePauliStrSum() + */ + +PauliStrSum createMyHamiltonian(int numQubits) { + + // we prepare a Heisenberg XYZ spin-ring Hamiltonian, + // i.e. H = -1/2 sum( Jx XX + Jy YY + Jz ZZ + h Z ) + // upon all nearest neighbour qubits, with periodicity. + // The coefficients must be real for H to be Hermitian + // and ergo its time-evolution operator to be unitary, + // although they must be represented with a qcomp type. + char* operators[] = {"XX", "YY", "ZZ", "Z"}; + qcomp coefficients[] = {.1, .2, .3, .4}; // Jx,Jy,Jz,h + + // we will populate the below arrays with 4*numQubits + // elements, bounded by 4*64 = 256 (MSVC hates VLAs) + int numTerms = 4 * numQubits; + PauliStr allStrings[256]; // [numTerms] + qcomp allCoeffs [256]; // [numTerms] + + int allInd = 0; + + // prepare all XX + YY + ZZ + for (int p=0; p<3; p++) { + for (int i=0; i to |psi(t)> = exp(-itH)|+> + * via Trotterisation, calculating the expected value + * = where Hamiltonian H and + * observable O are as prepared above. + */ + +int main() { + initQuESTEnv(); + + // prepare qureg=|0>, H and O + int numQubits = 20; + Qureg qureg = createQureg(numQubits); + PauliStrSum hamil = createMyHamiltonian(numQubits); + PauliStrSum observ = createMyObservable(numQubits); + + // init qureg=|+> and report qureg, H, O + initPlusState(qureg); + reportMyStructs(qureg, hamil, observ); + + // tidy reporting of below expectation values + setMaxNumReportedSigFigs(3); + setNumReportedNewlines(1); + + // evolve by repeatedly (each is a "step") Trotterising + // exp(-i dt H) with the specified order and repetitions. + qreal dt = 0.1; + int order = 4; + int reps = 5; + int steps = 20; + + for (int i=0; i + qreal time = dt * (i+1); + qreal expec = calcExpecPauliStrSum(qureg, observ); + + char label[50]; + snprintf(label, 50, "", time); + reportScalar(label, expec); + } + + reportStr(""); + + // preview the final state... + setNumReportedNewlines(2); + setMaxNumReportedItems(25, 25); + reportStr("[Final state]"); + reportQureg(qureg); + + // and some of its properties... + reportScalar("Normalisation", calcTotalProb(qureg)); + reportScalar("Probability of first qubit", calcProbOfQubitOutcome(qureg, 0, 0)); + + // including the overlap with |+> + for (int i=0; i", calcExpecPauliStrSum(qureg, observ)); + + // clean up + destroyQureg(qureg); + destroyPauliStrSum(hamil); + destroyPauliStrSum(observ); + finalizeQuESTEnv(); + return 0; +} diff --git a/examples/extended/dynamics.cpp b/examples/extended/dynamics.cpp new file mode 100644 index 000000000..ccea66f31 --- /dev/null +++ b/examples/extended/dynamics.cpp @@ -0,0 +1,185 @@ +#include "quest.h" +#include +#include + +using std::vector; +using std::string; + + + +/* + * Prepare a Hamiltonian H under which dyanmical + * evolution will be simulated via Trotterisation + * of unitary-time evolution operator e^(-itH). + * If the Hamiltonian was fixed/known in advance, + * we could instead use createInlinePauliStrSum() + */ + +PauliStrSum createMyHamiltonian(int numQubits) { + + // we prepare a Heisenberg XYZ spin-ring Hamiltonian, + // i.e. H = -1/2 sum( Jx XX + Jy YY + Jz ZZ + h Z ) + // upon all nearest neighbour qubits, with periodicity. + // The coefficients must be real for H to be Hermitian + // and ergo its time-evolution operator to be unitary, + // although they must be represented with a qcomp type. + vector operators = {"XX", "YY", "ZZ", "Z"}; + vector coefficients = {.1, .2, .3, .4}; // Jx,Jy,Jz,h + + // we will populate the below vectors with 4*numQubits + // elements which we could pre-allocate with .reserve, + // but we might incur Donald Knuth's justified wrath. + vector allStrings; + vector allCoeffs; + + // prepare all XX + YY + ZZ + for (int p=0; p<3; p++) { + for (int i=0; i targs = {i, (i+1)%numQubits}; + PauliStr str = getPauliStr(operators[p], targs); + + allStrings.push_back(str); + allCoeffs.push_back(coefficients[p]); + } + } + + // prepare Z + for (int i=0; i strings(numQubits); + vector coeffs(numQubits); + + for (int i=0; i to |psi(t)> = exp(-itH)|+> + * via Trotterisation, calculating the expected value + * = where Hamiltonian H and + * observable O are as prepared above. + */ + +int main() { + initQuESTEnv(); + + // prepare qureg=|0>, H and O + int numQubits = 20; + Qureg qureg = createQureg(numQubits); + PauliStrSum hamil = createMyHamiltonian(numQubits); + PauliStrSum observ = createMyObservable(numQubits); + + // init qureg=|+> and report qureg, H, O + initPlusState(qureg); + reportMyStructs(qureg, hamil, observ); + + // tidy reporting of below expectation values + setMaxNumReportedSigFigs(3); + setNumReportedNewlines(1); + + // evolve by repeatedly (each is a "step") Trotterising + // exp(-i dt H) with the specified order and repetitions. + qreal dt = 0.1; + int order = 4; + int reps = 5; + int steps = 20; + + for (int i=0; i + qreal time = dt * (i+1); + qreal expec = calcExpecPauliStrSum(qureg, observ); + reportScalar("", expec); + } + + reportStr(""); + + // preview the final state... + setNumReportedNewlines(2); + setMaxNumReportedItems(25, 25); + reportStr("[Final state]"); + reportQureg(qureg); + + // and some of its properties... + reportScalar("Normalisation", calcTotalProb(qureg)); + reportScalar("Probability of first qubit", calcProbOfQubitOutcome(qureg, 0, 0)); + + // including the overlap with |+> + for (int i=0; i", calcExpecPauliStrSum(qureg, observ)); + + // clean up + destroyQureg(qureg); + destroyPauliStrSum(hamil); + destroyPauliStrSum(observ); + finalizeQuESTEnv(); + return 0; +} diff --git a/examples/isolated/CMakeLists.txt b/examples/isolated/CMakeLists.txt new file mode 100644 index 000000000..5880c2ac0 --- /dev/null +++ b/examples/isolated/CMakeLists.txt @@ -0,0 +1,3 @@ +# @author Tyson Jones + +add_all_local_examples() diff --git a/examples/numbers/arithmetic.c b/examples/isolated/complex_arithmetic.c similarity index 100% rename from examples/numbers/arithmetic.c rename to examples/isolated/complex_arithmetic.c diff --git a/examples/numbers/arithmetic.cpp b/examples/isolated/complex_arithmetic.cpp similarity index 100% rename from examples/numbers/arithmetic.cpp rename to examples/isolated/complex_arithmetic.cpp diff --git a/examples/krausmaps/initialisation.c b/examples/isolated/initialising_krausmaps.c similarity index 100% rename from examples/krausmaps/initialisation.c rename to examples/isolated/initialising_krausmaps.c diff --git a/examples/krausmaps/initialisation.cpp b/examples/isolated/initialising_krausmaps.cpp similarity index 100% rename from examples/krausmaps/initialisation.cpp rename to examples/isolated/initialising_krausmaps.cpp diff --git a/examples/matrices/initialisation.c b/examples/isolated/initialising_matrices.c similarity index 100% rename from examples/matrices/initialisation.c rename to examples/isolated/initialising_matrices.c diff --git a/examples/matrices/initialisation.cpp b/examples/isolated/initialising_matrices.cpp similarity index 100% rename from examples/matrices/initialisation.cpp rename to examples/isolated/initialising_matrices.cpp diff --git a/examples/paulis/initialisation.c b/examples/isolated/initialising_paulis.c similarity index 100% rename from examples/paulis/initialisation.c rename to examples/isolated/initialising_paulis.c diff --git a/examples/paulis/initialisation.cpp b/examples/isolated/initialising_paulis.cpp similarity index 100% rename from examples/paulis/initialisation.cpp rename to examples/isolated/initialising_paulis.cpp diff --git a/examples/superoperators/initialisation.c b/examples/isolated/initialising_superoperators.c similarity index 100% rename from examples/superoperators/initialisation.c rename to examples/isolated/initialising_superoperators.c diff --git a/examples/superoperators/initialisation.cpp b/examples/isolated/initialising_superoperators.cpp similarity index 100% rename from examples/superoperators/initialisation.cpp rename to examples/isolated/initialising_superoperators.cpp diff --git a/examples/reporters/env.c b/examples/isolated/reporting_environments.c similarity index 100% rename from examples/reporters/env.c rename to examples/isolated/reporting_environments.c diff --git a/examples/reporters/env.cpp b/examples/isolated/reporting_environments.cpp similarity index 100% rename from examples/reporters/env.cpp rename to examples/isolated/reporting_environments.cpp diff --git a/examples/reporters/matrices.c b/examples/isolated/reporting_matrices.c similarity index 100% rename from examples/reporters/matrices.c rename to examples/isolated/reporting_matrices.c diff --git a/examples/reporters/matrices.cpp b/examples/isolated/reporting_matrices.cpp similarity index 100% rename from examples/reporters/matrices.cpp rename to examples/isolated/reporting_matrices.cpp diff --git a/examples/reporters/paulis.c b/examples/isolated/reporting_paulis.c similarity index 100% rename from examples/reporters/paulis.c rename to examples/isolated/reporting_paulis.c diff --git a/examples/reporters/paulis.cpp b/examples/isolated/reporting_paulis.cpp similarity index 100% rename from examples/reporters/paulis.cpp rename to examples/isolated/reporting_paulis.cpp diff --git a/examples/reporters/qureg.c b/examples/isolated/reporting_quregs.c similarity index 100% rename from examples/reporters/qureg.c rename to examples/isolated/reporting_quregs.c diff --git a/examples/reporters/qureg.cpp b/examples/isolated/reporting_quregs.cpp similarity index 100% rename from examples/reporters/qureg.cpp rename to examples/isolated/reporting_quregs.cpp diff --git a/examples/debug/errorhandling.c b/examples/isolated/setting_errorhandler.c similarity index 100% rename from examples/debug/errorhandling.c rename to examples/isolated/setting_errorhandler.c diff --git a/examples/debug/errorhandling.cpp b/examples/isolated/setting_errorhandler.cpp similarity index 100% rename from examples/debug/errorhandling.cpp rename to examples/isolated/setting_errorhandler.cpp diff --git a/examples/krausmaps/CMakeLists.txt b/examples/krausmaps/CMakeLists.txt deleted file mode 100644 index 0aaa16688..000000000 --- a/examples/krausmaps/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -# @author Oliver Thomson Brown -# @author Erich Essmann (updating rpath) - -add_executable(krausmap_cpp_initialisation - initialisation.cpp -) - -target_link_libraries(krausmap_cpp_initialisation PUBLIC QuEST) - -install(TARGETS krausmap_cpp_initialisation - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/krausmaps -) -set_target_properties(krausmap_cpp_initialisation - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME "cpp_initialisation" -) - -add_executable(krausmap_c_initialisation - initialisation.c -) - -target_link_libraries(krausmap_c_initialisation PUBLIC QuEST) - -install(TARGETS krausmap_c_initialisation - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/krausmaps -) -set_target_properties(krausmap_c_initialisation - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME "c_initialisation" -) \ No newline at end of file diff --git a/examples/matrices/CMakeLists.txt b/examples/matrices/CMakeLists.txt deleted file mode 100644 index a0cf2f5a9..000000000 --- a/examples/matrices/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -# @author Oliver Thomson Brown -# @author Erich Essmann (updating rpath) - -add_executable(matrices_cpp_initialisation - initialisation.cpp -) - -target_link_libraries(matrices_cpp_initialisation PUBLIC QuEST) - -install(TARGETS matrices_cpp_initialisation - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/matrices -) -set_target_properties(matrices_cpp_initialisation - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME "cpp_initialisation" -) - -add_executable(matrices_c_initialisation - initialisation.c -) - -target_link_libraries(matrices_c_initialisation PUBLIC QuEST) - -install(TARGETS matrices_c_initialisation - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/matrices -) -set_target_properties(matrices_c_initialisation - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME "c_initialisation" -) \ No newline at end of file diff --git a/examples/numbers/CMakeLists.txt b/examples/numbers/CMakeLists.txt deleted file mode 100644 index 1f4a23045..000000000 --- a/examples/numbers/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -# @author Oliver Thomson Brown -# @author Erich Essmann (updating rpath) - -add_executable(cpp_arithmetic - arithmetic.cpp -) - -target_link_libraries(cpp_arithmetic PUBLIC QuEST) - -install(TARGETS cpp_arithmetic - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/numbers -) -set_target_properties(cpp_arithmetic - PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" -) - -add_executable(c_arithmetic - arithmetic.c -) - -target_link_libraries(c_arithmetic PUBLIC QuEST) - -install(TARGETS c_arithmetic - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/numbers -) -set_target_properties(c_arithmetic - PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" -) \ No newline at end of file diff --git a/examples/paulis/CMakeLists.txt b/examples/paulis/CMakeLists.txt deleted file mode 100644 index 353026523..000000000 --- a/examples/paulis/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -# @author Oliver Thomson Brown -# @author Erich Essmann (updating rpath) - -add_executable(paulis_cpp_initialisation - initialisation.cpp -) - -target_link_libraries(paulis_cpp_initialisation PUBLIC QuEST) - -install(TARGETS paulis_cpp_initialisation - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/paulis -) -set_target_properties(paulis_cpp_initialisation - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME "cpp_initialisation" -) - -add_executable(paulis_c_initialisation - initialisation.c -) - -target_link_libraries(paulis_c_initialisation PUBLIC QuEST) - -install(TARGETS paulis_c_initialisation - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/paulis -) -set_target_properties(paulis_c_initialisation - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME c_initialisation -) \ No newline at end of file diff --git a/examples/reporters/CMakeLists.txt b/examples/reporters/CMakeLists.txt deleted file mode 100644 index f0e910a39..000000000 --- a/examples/reporters/CMakeLists.txt +++ /dev/null @@ -1,130 +0,0 @@ -# @author Oliver Thomson Brown -# @author Erich Essmann (updating rpath) - -add_executable(reporters_cpp_env - env.cpp -) - -target_link_libraries(reporters_cpp_env PUBLIC QuEST) - -install(TARGETS reporters_cpp_env - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/reporters -) -set_target_properties(reporters_cpp_env - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME "cpp_env" -) - -add_executable(reporters_c_env - env.c -) - -target_link_libraries(reporters_c_env PUBLIC QuEST) - -install(TARGETS reporters_c_env - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/reporters -) -set_target_properties(reporters_c_env - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}}" - OUTPUT_NAME "c_env" -) - -add_executable(reporters_cpp_matrices - matrices.cpp -) - -target_link_libraries(reporters_cpp_matrices PUBLIC QuEST) - -install(TARGETS reporters_cpp_matrices - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/reporters -) -set_target_properties(reporters_cpp_matrices - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME "cpp_matrices" -) - -add_executable(reporters_c_matrices - matrices.c -) - -target_link_libraries(reporters_c_matrices PUBLIC QuEST) - -install(TARGETS reporters_c_matrices - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/reporters -) -set_target_properties(reporters_c_matrices - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME "c_matrices" -) - -add_executable(reporters_cpp_paulis - paulis.cpp -) - -target_link_libraries(reporters_cpp_paulis PUBLIC QuEST) - -install(TARGETS reporters_cpp_paulis - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/reporters -) -set_target_properties(reporters_cpp_paulis - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME "cpp_paulis" -) - -add_executable(reporters_c_paulis - paulis.c -) - -target_link_libraries(reporters_c_paulis PUBLIC QuEST) - -install(TARGETS reporters_c_paulis - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/reporters -) -set_target_properties(reporters_c_paulis - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME "c_paulis" -) - -add_executable(reporters_cpp_qureg - qureg.cpp -) - -target_link_libraries(reporters_cpp_qureg PUBLIC QuEST) - -install(TARGETS reporters_cpp_qureg - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/reporters -) -set_target_properties(reporters_cpp_qureg - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME "cpp_qureg" -) - -add_executable(reporters_c_qureg - qureg.c -) - -target_link_libraries(reporters_c_qureg PUBLIC QuEST) - -install(TARGETS reporters_c_qureg - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/reporters -) -set_target_properties(reporters_c_qureg - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME "c_qureg" -) \ No newline at end of file diff --git a/examples/superoperators/CMakeLists.txt b/examples/superoperators/CMakeLists.txt deleted file mode 100644 index b495f410e..000000000 --- a/examples/superoperators/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -# @author Oliver Thomson Brown -# @author Erich Essmann (updating rpath) - -add_executable(superoperators_cpp_initialisation - initialisation.cpp -) - -target_link_libraries(superoperators_cpp_initialisation PUBLIC QuEST) - -install(TARGETS superoperators_cpp_initialisation - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/superoperators -) -set_target_properties(superoperators_cpp_initialisation - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME "cpp_initialisation" -) - -add_executable(superoperators_c_initialisation - initialisation.c -) - -target_link_libraries(superoperators_c_initialisation PUBLIC QuEST) - -install(TARGETS superoperators_c_initialisation - RUNTIME - DESTINATION ${CMAKE_INSTALL_BINDIR}/examples/superoperators -) -set_target_properties(superoperators_c_initialisation - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" - OUTPUT_NAME c_initialisation -) \ No newline at end of file diff --git a/examples/tutorials/min_example.cpp b/examples/tutorials/min_example.c similarity index 80% rename from examples/tutorials/min_example.cpp rename to examples/tutorials/min_example.c index e20bfdfd7..6cba5a0b0 100644 --- a/examples/tutorials/min_example.cpp +++ b/examples/tutorials/min_example.c @@ -7,7 +7,6 @@ */ #include "quest.h" -#include int main(void) { @@ -21,10 +20,8 @@ int main(void) { reportQureg(qureg); qreal prob = calcTotalProb(qureg); + reportScalar("Total probability", prob); - if (getQuESTEnv().rank == 0) - std::cout << "Total probability: " << prob << std::endl; - destroyQureg(qureg); finalizeQuESTEnv(); From 1c051cf38b227896d1c6316fbd5a3d9ce96e097b Mon Sep 17 00:00:00 2001 From: Erich Essmann Date: Thu, 1 May 2025 12:28:32 +0100 Subject: [PATCH 04/12] improved build and CI (#601) Erich (build): - adjusted install interface paths to use CMAKE_INSTALL_INCLUDEDIR - added platform-agnostic RPATH handling via helper function setup_quest_rpath - set RPATH origin for dynamic linking - passed QuEST version info to CMake Tyson (CI): - run compiled examples to test for link-time errors - temporarily disabled LCOV reporting to PRs --------- Co-authored-by: Tyson Jones --- .github/workflows/audit.yml | 5 ++++ .github/workflows/compile.yml | 19 ++++++++++++++- CMakeLists.txt | 44 +++++++++++++++++++++++++++-------- 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index f6cbb5e22..583749df4 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -188,3 +188,8 @@ jobs: coverage-files: ./${{ env.tracefile }} minimum-coverage: ${{ env.min_coverage }} github-token: ${{ secrets.GITHUB_TOKEN }} + + # temporarily DISABLING above reporting of LCOV results in + # PR since they're not yet representative and will only + # confuse incoming unitaryHACK contributors + if: false diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 6754cc7b5..8cc4d0eec 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -7,7 +7,9 @@ # compilers (like libomp, CUDA, ROCm). Compilation # includes the v4 unit and integration tests, the # deprecated v3 tests (when possible), and all the -# example programs. No compiled execs are run however. +# example programs. One example executable is then +# run (both C and C++ versions) to ensure the build +# was successful and does not cause link-time errors. # Note that ARM compilation is not yet tested here, # but in fact Linux ARM is used by a paid test runner. # @@ -144,6 +146,8 @@ jobs: cuda_arch: 70 hip_arch: gfx801 rocm_path: /opt/rocm/bin + example_dir: build/examples/isolated + example_fn_pref: reporting_quregs # perform the job steps: @@ -232,3 +236,16 @@ jobs: # force 'Release' build (needed by MSVC to enable optimisations) - name: Compile run: cmake --build ${{ env.build_dir }} --config Release --parallel + + # attempt to run the compiled executable, testing for link-time errors, + # logging stdout and stderr to file (to verify the executable actually ran) + - name: Run (Windows) + if: ${{ matrix.os == 'windows-latest' }} + run: | + ./${{ env.example_dir }}/Release/${{ env.example_fn_pref }}_c.exe + ./${{ env.example_dir }}/Release/${{ env.example_fn_pref }}_cpp.exe + - name: Run (non-Windows) + if: ${{ matrix.os != 'windows-latest' }} + run: | + ./${{ env.example_dir }}/${{ env.example_fn_pref }}_c + ./${{ env.example_dir }}/${{ env.example_fn_pref }}_cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b2b941c5e..d48dcebb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -250,11 +250,15 @@ add_library(QuEST::QuEST ALIAS QuEST) # Set include directories target_include_directories(QuEST - PUBLIC - $ - $ - $ - $ + PUBLIC + $ + $ + $ + $ +) +set_target_properties(QuEST PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} ) # Add required C and C++ standards @@ -436,15 +440,34 @@ install(TARGETS min_example RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) -set_target_properties(min_example - PROPERTIES - INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}" -) if (BUILD_EXAMPLES) add_subdirectory(examples) endif() +## RATH +set(BUILD_RPATH_USE_ORIGIN ON) +if(APPLE) + set(_RPATH_ORIGIN "@loader_path") +else() + set(_RPATH_ORIGIN "$ORIGIN") +endif() + +set(_INSTALL_RPATH "${_RPATH_ORIGIN}/../${CMAKE_INSTALL_LIBDIR}") +set(_BUILD_RPATH "${_RPATH_ORIGIN};$") + +# A tiny helper function so you can call it for every target +function(setup_quest_rpath tgt) + set_target_properties(${tgt} PROPERTIES + BUILD_RPATH "${_BUILD_RPATH}" + INSTALL_RPATH "${_INSTALL_RPATH}" + # keeps RPATH from being stripped when installing + INSTALL_RPATH_USE_LINK_PATH TRUE + ) +endfunction() + +setup_quest_rpath(QuEST) +setup_quest_rpath(min_example) ## User Source if (USER_SOURCE AND NOT OUTPUT_EXE) @@ -459,9 +482,10 @@ if (USER_SOURCE AND OUTPUT_EXE) add_executable(${OUTPUT_EXE} ${USER_SOURCE}) target_link_libraries(${OUTPUT_EXE} PUBLIC QuEST) install(TARGETS ${OUTPUT_EXE} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) - set_target_properties(${OUTPUT_EXE} PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}") + setup_quest_rpath(${OUTPUT_EXE}) endif() + ## Tests if (ENABLE_TESTING) From ce95cf2e9c7759c11c47333677b309fbb88aa0d1 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Tue, 6 May 2025 19:18:34 +0200 Subject: [PATCH 05/12] standardising unit-test includes so that external contributors (and importantly right now, example PRs) can contribute new, self-contained unit test code without needing to incorporate new headers --- tests/unit/calculations.cpp | 3 ++- tests/unit/decoherence.cpp | 2 ++ tests/unit/initialisations.cpp | 3 +++ tests/unit/types.cpp | 5 ++++- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/unit/calculations.cpp b/tests/unit/calculations.cpp index 3cbe22c9f..f5d30c757 100644 --- a/tests/unit/calculations.cpp +++ b/tests/unit/calculations.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include "tests/utils/qvector.hpp" @@ -29,8 +30,8 @@ #include #include +using Catch::Matchers::ContainsSubstring; using std::vector; -using namespace Catch::Matchers; diff --git a/tests/unit/decoherence.cpp b/tests/unit/decoherence.cpp index 1a9ddd1cb..cfa1328bd 100644 --- a/tests/unit/decoherence.cpp +++ b/tests/unit/decoherence.cpp @@ -10,6 +10,7 @@ #include "quest/include/quest.h" #include +#include #include #include "tests/utils/qvector.hpp" @@ -26,6 +27,7 @@ #include #include +using Catch::Matchers::ContainsSubstring; using std::vector; diff --git a/tests/unit/initialisations.cpp b/tests/unit/initialisations.cpp index cbd35cf03..e42fd099d 100644 --- a/tests/unit/initialisations.cpp +++ b/tests/unit/initialisations.cpp @@ -10,6 +10,7 @@ #include "quest/include/quest.h" #include +#include #include #include "tests/utils/qvector.hpp" @@ -24,6 +25,8 @@ #include "tests/utils/measure.hpp" #include "tests/utils/random.hpp" +using Catch::Matchers::ContainsSubstring; + /* diff --git a/tests/unit/types.cpp b/tests/unit/types.cpp index fdc5aff69..d84c846f7 100644 --- a/tests/unit/types.cpp +++ b/tests/unit/types.cpp @@ -10,6 +10,7 @@ #include "quest/include/quest.h" #include +#include #include "tests/utils/qvector.hpp" #include "tests/utils/qmatrix.hpp" @@ -21,6 +22,8 @@ #include "tests/utils/macros.hpp" #include "tests/utils/random.hpp" +using Catch::Matchers::ContainsSubstring; + /* @@ -98,4 +101,4 @@ void reportStr(std::string str); void reportScalar(const char* label, qcomp num); void reportScalar(const char* label, qreal num); void reportScalar(std::string label, qcomp num); -void reportScalar(std::string label, qreal num); \ No newline at end of file +void reportScalar(std::string label, qreal num); From 9be1dfd4b7359c45fd7732d41ee611622cc695a1 Mon Sep 17 00:00:00 2001 From: Luc Jaulmes Date: Thu, 8 May 2025 20:13:54 +0100 Subject: [PATCH 06/12] patched CMake install (#616) This resolves the issues highlighted in #611 while maintaining QuEST's header include structure in the source --- CMakeLists.txt | 57 +++++++++++++------ cmake/QuESTConfig.cmake.in | 2 +- quest/include/CMakeLists.txt | 5 +- quest/include/deprecated.h | 2 +- quest/include/{quest.h => quest.h.in} | 11 +++- tests/deprecated/test_calculations.cpp | 2 +- tests/deprecated/test_data_structures.cpp | 2 +- tests/deprecated/test_gates.cpp | 2 +- tests/deprecated/test_main.cpp | 2 +- tests/deprecated/test_operators.cpp | 2 +- .../deprecated/test_state_initialisations.cpp | 2 +- tests/deprecated/test_unitaries.cpp | 2 +- tests/deprecated/test_utilities.cpp | 2 +- tests/deprecated/test_utilities.hpp | 2 +- tests/integration/densitymatrix.cpp | 2 +- tests/main.cpp | 2 +- tests/unit/calculations.cpp | 2 +- tests/unit/channels.cpp | 2 +- tests/unit/debug.cpp | 2 +- tests/unit/decoherence.cpp | 2 +- tests/unit/environment.cpp | 2 +- tests/unit/initialisations.cpp | 2 +- tests/unit/matrices.cpp | 2 +- tests/unit/operations.cpp | 2 +- tests/unit/paulis.cpp | 2 +- tests/unit/qureg.cpp | 2 +- tests/unit/types.cpp | 2 +- tests/utils/cache.cpp | 2 +- tests/utils/cache.hpp | 2 +- tests/utils/compare.cpp | 2 +- tests/utils/compare.hpp | 2 +- tests/utils/convert.cpp | 2 +- tests/utils/convert.hpp | 2 +- tests/utils/lists.cpp | 2 +- tests/utils/lists.hpp | 2 +- tests/utils/measure.cpp | 2 +- tests/utils/measure.hpp | 2 +- tests/utils/qmatrix.hpp | 2 +- tests/utils/qvector.hpp | 2 +- tests/utils/random.cpp | 2 +- tests/utils/random.hpp | 2 +- 41 files changed, 90 insertions(+), 59 deletions(-) rename quest/include/{quest.h => quest.h.in} (88%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d48dcebb7..0b2cc5694 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,22 @@ message(STATUS "Library will be named lib${LIB_NAME}. Set LIB_NAME to modify.") option(VERBOSE_LIB_NAME "Modify library name based on compilation configuration. Turned OFF by default." OFF) message(STATUS "Verbose library naming is turned ${VERBOSE_LIB_NAME}. Set VERBOSE_LIB_NAME to modify.") +if (VERBOSE_LIB_NAME) + # Same headers will be used for several verbosely-named libraries + set(MULTI_LIB_HEADERS 1) + function(compile_option VAR VALUE) + target_compile_definitions(QuEST PUBLIC ${VAR}=${VALUE}) + endfunction() +else() + # Headers will be used for a single library with a single valid configuration + set(MULTI_LIB_HEADERS 0) + function(compile_option VAR VALUE) + target_compile_definitions(QuEST PRIVATE ${VAR}=${VALUE}) + set(${VAR} ${VALUE}) + endfunction() +endif() + + # Precision set(FLOAT_PRECISION 2 CACHE @@ -253,8 +269,8 @@ target_include_directories(QuEST PUBLIC $ $ + $ $ - $ ) set_target_properties(QuEST PROPERTIES VERSION ${PROJECT_VERSION} @@ -283,7 +299,7 @@ target_compile_options(QuEST # Set user options -target_compile_definitions(QuEST PUBLIC FLOAT_PRECISION=${FLOAT_PRECISION}) +compile_option(FLOAT_PRECISION ${FLOAT_PRECISION}) if (ENABLE_MULTITHREADING) @@ -299,7 +315,7 @@ if (ENABLE_MULTITHREADING) message(FATAL_ERROR ${ErrorMsg}) endif() - target_compile_definitions(QuEST PUBLIC COMPILE_OPENMP=1) + compile_option(COMPILE_OPENMP 1) target_link_libraries(QuEST PRIVATE OpenMP::OpenMP_CXX @@ -317,14 +333,14 @@ else() target_compile_options(QuEST PRIVATE $<$:-Wno-unknown-pragmas>) endif() - target_compile_definitions(QuEST PUBLIC COMPILE_OPENMP=0) + compile_option(COMPILE_OPENMP 0) endif() if (ENABLE_DISTRIBUTION) find_package(MPI REQUIRED COMPONENTS CXX ) - target_compile_definitions(QuEST PUBLIC COMPILE_MPI=1) + compile_option(COMPILE_MPI 1) target_link_libraries(QuEST PRIVATE MPI::MPI_CXX @@ -333,7 +349,7 @@ if (ENABLE_DISTRIBUTION) string(CONCAT LIB_NAME ${LIB_NAME} "+mpi") endif() else() - target_compile_definitions(QuEST PUBLIC COMPILE_MPI=0) + compile_option(COMPILE_MPI 0) endif() if (ENABLE_CUDA) @@ -357,14 +373,14 @@ endif() if (ENABLE_CUQUANTUM) find_package(CUQUANTUM REQUIRED) - target_compile_definitions(QuEST PUBLIC COMPILE_CUQUANTUM=1) + compile_option(COMPILE_CUQUANTUM 1) target_link_libraries(QuEST PRIVATE CUQUANTUM::cuStateVec) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ON) if (VERBOSE_LIB_NAME) string(CONCAT LIB_NAME ${LIB_NAME} "+cuquantum") endif() else() - target_compile_definitions(QuEST PUBLIC COMPILE_CUQUANTUM=0) + compile_option(COMPILE_CUQUANTUM 0) endif() if (ENABLE_HIP) @@ -384,7 +400,7 @@ if (ENABLE_HIP) find_package(HIP REQUIRED) message(STATUS "Found HIP: " ${HIP_VERSION}) - target_compile_definitions(QuEST PUBLIC COMPILE_CUQUANTUM=0) + compile_option(COMPILE_CUQUANTUM 0) target_link_libraries(QuEST PRIVATE hip::host) if (VERBOSE_LIB_NAME) @@ -393,9 +409,9 @@ if (ENABLE_HIP) endif() if (ENABLE_CUDA OR ENABLE_HIP) - target_compile_definitions(QuEST PUBLIC COMPILE_CUDA=1) + compile_option(COMPILE_CUDA 1) else() - target_compile_definitions(QuEST PUBLIC COMPILE_CUDA=0) + compile_option(COMPILE_CUDA 0) endif() if (ENABLE_DEPRECATED_API) @@ -533,7 +549,7 @@ set(QuEST_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/QuEST") # Write QuESTConfigVersion.cmake write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/QuESTConfigVersion.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}ConfigVersion.cmake" VERSION ${PROJECT_VERSION} COMPATIBILITY AnyNewerVersion ) @@ -541,19 +557,28 @@ write_basic_package_version_file( # Configure QuESTConfig.cmake (from template) configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/QuESTConfig.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/QuESTConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}Config.cmake" INSTALL_DESTINATION "${QuEST_INSTALL_CONFIGDIR}" ) # Install them install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/QuESTConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/QuESTConfigVersion.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}Config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}ConfigVersion.cmake" DESTINATION "${QuEST_INSTALL_CONFIGDIR}" ) +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/quest.h" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" +) + +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/quest/include" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/quest" + FILES_MATCHING PATTERN "*.h" +) + install(EXPORT QuESTTargets - FILE QuESTTargets.cmake + FILE "${LIB_NAME}Targets.cmake" NAMESPACE QuEST:: DESTINATION "${QuEST_INSTALL_CONFIGDIR}" ) diff --git a/cmake/QuESTConfig.cmake.in b/cmake/QuESTConfig.cmake.in index b28896e95..c41c91aa1 100644 --- a/cmake/QuESTConfig.cmake.in +++ b/cmake/QuESTConfig.cmake.in @@ -1,4 +1,4 @@ # @author Erich Essmann @PACKAGE_INIT@ -include("${CMAKE_CURRENT_LIST_DIR}/QuESTTargets.cmake") \ No newline at end of file +include("${CMAKE_CURRENT_LIST_DIR}/@LIB_NAME@Targets.cmake") diff --git a/quest/include/CMakeLists.txt b/quest/include/CMakeLists.txt index 44b5325f6..aec6285ea 100644 --- a/quest/include/CMakeLists.txt +++ b/quest/include/CMakeLists.txt @@ -1,7 +1,4 @@ # @author Oliver Thomson Brown # @author Erich Essmann -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DESTINATION "${CMAKE_INSTALL_PREFIX}" - FILES_MATCHING PATTERN "*.h" -) +configure_file(quest.h.in "${CMAKE_BINARY_DIR}/include/quest.h" @ONLY) diff --git a/quest/include/deprecated.h b/quest/include/deprecated.h index b26e94804..efd7afd9d 100644 --- a/quest/include/deprecated.h +++ b/quest/include/deprecated.h @@ -18,7 +18,7 @@ #ifndef DEPRECATED_H #define DEPRECATED_H -#include "quest/include/quest.h" +#include "quest.h" #include "stdlib.h" diff --git a/quest/include/quest.h b/quest/include/quest.h.in similarity index 88% rename from quest/include/quest.h rename to quest/include/quest.h.in index e3fde6756..383b42c04 100644 --- a/quest/include/quest.h +++ b/quest/include/quest.h.in @@ -30,6 +30,15 @@ #define QUEST_H +#if !@MULTI_LIB_HEADERS@ +#cmakedefine FLOAT_PRECISION @FLOAT_PRECISION@ +#cmakedefine01 COMPILE_MPI +#cmakedefine01 COMPILE_OPENMP +#cmakedefine01 COMPILE_CUDA +#cmakedefine01 COMPILE_CUQUANTUM +#endif + + // include version first so it is accessible to // debuggers in case a subsequent include fails #include "quest/include/version.h" @@ -60,4 +69,4 @@ -#endif // QUEST_H \ No newline at end of file +#endif // QUEST_H diff --git a/tests/deprecated/test_calculations.cpp b/tests/deprecated/test_calculations.cpp index 2bf738f0e..3ed8f560e 100644 --- a/tests/deprecated/test_calculations.cpp +++ b/tests/deprecated/test_calculations.cpp @@ -20,7 +20,7 @@ // warnings issued by its compilation #define INCLUDE_DEPRECATED_FUNCTIONS 1 #define DISABLE_DEPRECATION_WARNINGS 1 -#include "quest/include/quest.h" +#include "quest.h" #include "test_utilities.hpp" diff --git a/tests/deprecated/test_data_structures.cpp b/tests/deprecated/test_data_structures.cpp index 1cbd1b596..258d83f75 100644 --- a/tests/deprecated/test_data_structures.cpp +++ b/tests/deprecated/test_data_structures.cpp @@ -20,7 +20,7 @@ // warnings issued by its compilation #define INCLUDE_DEPRECATED_FUNCTIONS 1 #define DISABLE_DEPRECATION_WARNINGS 1 -#include "quest/include/quest.h" +#include "quest.h" #include "test_utilities.hpp" diff --git a/tests/deprecated/test_gates.cpp b/tests/deprecated/test_gates.cpp index c10e22443..f8c175666 100644 --- a/tests/deprecated/test_gates.cpp +++ b/tests/deprecated/test_gates.cpp @@ -23,7 +23,7 @@ // warnings issued by its compilation #define INCLUDE_DEPRECATED_FUNCTIONS 1 #define DISABLE_DEPRECATION_WARNINGS 1 -#include "quest/include/quest.h" +#include "quest.h" #include "test_utilities.hpp" diff --git a/tests/deprecated/test_main.cpp b/tests/deprecated/test_main.cpp index db507da56..fc75d8190 100644 --- a/tests/deprecated/test_main.cpp +++ b/tests/deprecated/test_main.cpp @@ -21,7 +21,7 @@ #define INCLUDE_DEPRECATED_FUNCTIONS 1 #define DISABLE_DEPRECATION_WARNINGS 1 -#include "quest/include/quest.h" +#include "quest.h" #include "test_utilities.hpp" #include diff --git a/tests/deprecated/test_operators.cpp b/tests/deprecated/test_operators.cpp index 6e28ab584..6130ad3b8 100644 --- a/tests/deprecated/test_operators.cpp +++ b/tests/deprecated/test_operators.cpp @@ -20,7 +20,7 @@ // warnings issued by its compilation #define INCLUDE_DEPRECATED_FUNCTIONS 1 #define DISABLE_DEPRECATION_WARNINGS 1 -#include "quest/include/quest.h" +#include "quest.h" #include "test_utilities.hpp" diff --git a/tests/deprecated/test_state_initialisations.cpp b/tests/deprecated/test_state_initialisations.cpp index f961b8564..160721f7a 100644 --- a/tests/deprecated/test_state_initialisations.cpp +++ b/tests/deprecated/test_state_initialisations.cpp @@ -16,7 +16,7 @@ #define INCLUDE_DEPRECATED_FUNCTIONS 1 #define DISABLE_DEPRECATION_WARNINGS 1 -#include "quest/include/quest.h" +#include "quest.h" #include "test_utilities.hpp" diff --git a/tests/deprecated/test_unitaries.cpp b/tests/deprecated/test_unitaries.cpp index 1e86af330..6414880d1 100644 --- a/tests/deprecated/test_unitaries.cpp +++ b/tests/deprecated/test_unitaries.cpp @@ -20,7 +20,7 @@ // warnings issued by its compilation #define INCLUDE_DEPRECATED_FUNCTIONS 1 #define DISABLE_DEPRECATION_WARNINGS 1 -#include "quest/include/quest.h" +#include "quest.h" #include "test_utilities.hpp" diff --git a/tests/deprecated/test_utilities.cpp b/tests/deprecated/test_utilities.cpp index f8bf57376..27ef8af9f 100644 --- a/tests/deprecated/test_utilities.cpp +++ b/tests/deprecated/test_utilities.cpp @@ -11,7 +11,7 @@ #define INCLUDE_DEPRECATED_FUNCTIONS 1 #define DISABLE_DEPRECATION_WARNINGS 1 -#include "quest/include/quest.h" +#include "quest.h" #include "test_utilities.hpp" diff --git a/tests/deprecated/test_utilities.hpp b/tests/deprecated/test_utilities.hpp index cc9b815cf..8145c3f65 100644 --- a/tests/deprecated/test_utilities.hpp +++ b/tests/deprecated/test_utilities.hpp @@ -9,7 +9,7 @@ #ifndef QUEST_TEST_UTILS_H #define QUEST_TEST_UTILS_H -#include "quest/include/quest.h" +#include "quest.h" #include diff --git a/tests/integration/densitymatrix.cpp b/tests/integration/densitymatrix.cpp index d926ed7e6..2c28a934e 100644 --- a/tests/integration/densitymatrix.cpp +++ b/tests/integration/densitymatrix.cpp @@ -7,7 +7,7 @@ * @author Tyson Jones */ -#include "quest/include/quest.h" +#include "quest.h" #include #include diff --git a/tests/main.cpp b/tests/main.cpp index 190b58ef1..d2ddd52cc 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -49,7 +49,7 @@ #include #include -#include "quest/include/quest.h" +#include "quest.h" #include "tests/utils/cache.hpp" #include "tests/utils/macros.hpp" #include "tests/utils/random.hpp" diff --git a/tests/unit/calculations.cpp b/tests/unit/calculations.cpp index f5d30c757..e0b4e9962 100644 --- a/tests/unit/calculations.cpp +++ b/tests/unit/calculations.cpp @@ -7,7 +7,7 @@ * @ingroup unittests */ -#include "quest/include/quest.h" +#include "quest.h" #include #include diff --git a/tests/unit/channels.cpp b/tests/unit/channels.cpp index 1342402fd..b0a7ab314 100644 --- a/tests/unit/channels.cpp +++ b/tests/unit/channels.cpp @@ -7,7 +7,7 @@ * @ingroup unittests */ -#include "quest/include/quest.h" +#include "quest.h" #include #include diff --git a/tests/unit/debug.cpp b/tests/unit/debug.cpp index bc20a0a56..07a967493 100644 --- a/tests/unit/debug.cpp +++ b/tests/unit/debug.cpp @@ -7,7 +7,7 @@ * @ingroup unittests */ -#include "quest/include/quest.h" +#include "quest.h" #include #include diff --git a/tests/unit/decoherence.cpp b/tests/unit/decoherence.cpp index cfa1328bd..5fc373a44 100644 --- a/tests/unit/decoherence.cpp +++ b/tests/unit/decoherence.cpp @@ -7,7 +7,7 @@ * @ingroup unittests */ -#include "quest/include/quest.h" +#include "quest.h" #include #include diff --git a/tests/unit/environment.cpp b/tests/unit/environment.cpp index 23c9af8bf..6fc6d21ec 100644 --- a/tests/unit/environment.cpp +++ b/tests/unit/environment.cpp @@ -7,7 +7,7 @@ * @ingroup unittests */ -#include "quest/include/quest.h" +#include "quest.h" #include #include diff --git a/tests/unit/initialisations.cpp b/tests/unit/initialisations.cpp index e42fd099d..90a27ad75 100644 --- a/tests/unit/initialisations.cpp +++ b/tests/unit/initialisations.cpp @@ -7,7 +7,7 @@ * @ingroup unittests */ -#include "quest/include/quest.h" +#include "quest.h" #include #include diff --git a/tests/unit/matrices.cpp b/tests/unit/matrices.cpp index 01db8bddd..591e3bc7b 100644 --- a/tests/unit/matrices.cpp +++ b/tests/unit/matrices.cpp @@ -7,7 +7,7 @@ * @ingroup unittests */ -#include "quest/include/quest.h" +#include "quest.h" #include #include diff --git a/tests/unit/operations.cpp b/tests/unit/operations.cpp index 6f168d05f..6676dfba9 100644 --- a/tests/unit/operations.cpp +++ b/tests/unit/operations.cpp @@ -15,7 +15,7 @@ * @ingroup unittests */ -#include "quest/include/quest.h" +#include "quest.h" #include #include diff --git a/tests/unit/paulis.cpp b/tests/unit/paulis.cpp index 6d955fed2..f18b57228 100644 --- a/tests/unit/paulis.cpp +++ b/tests/unit/paulis.cpp @@ -7,7 +7,7 @@ * @ingroup unittests */ -#include "quest/include/quest.h" +#include "quest.h" #include #include diff --git a/tests/unit/qureg.cpp b/tests/unit/qureg.cpp index e0febd18b..aaf3bb0cd 100644 --- a/tests/unit/qureg.cpp +++ b/tests/unit/qureg.cpp @@ -7,7 +7,7 @@ * @ingroup unittests */ -#include "quest/include/quest.h" +#include "quest.h" #include #include diff --git a/tests/unit/types.cpp b/tests/unit/types.cpp index d84c846f7..dfce4005c 100644 --- a/tests/unit/types.cpp +++ b/tests/unit/types.cpp @@ -7,7 +7,7 @@ * @ingroup unittests */ -#include "quest/include/quest.h" +#include "quest.h" #include #include diff --git a/tests/utils/cache.cpp b/tests/utils/cache.cpp index b49b3c417..21dee8482 100644 --- a/tests/utils/cache.cpp +++ b/tests/utils/cache.cpp @@ -5,7 +5,7 @@ * @author Tyson Jones */ -#include "quest/include/quest.h" +#include "quest.h" #include "macros.hpp" #include "qvector.hpp" diff --git a/tests/utils/cache.hpp b/tests/utils/cache.hpp index 15bfb969d..ec8c71c7e 100644 --- a/tests/utils/cache.hpp +++ b/tests/utils/cache.hpp @@ -12,7 +12,7 @@ #ifndef CACHE_HPP #define CACHE_HPP -#include "quest/include/quest.h" +#include "quest.h" #include "qvector.hpp" #include "qmatrix.hpp" diff --git a/tests/utils/compare.cpp b/tests/utils/compare.cpp index 59be83bf2..c35585434 100644 --- a/tests/utils/compare.cpp +++ b/tests/utils/compare.cpp @@ -12,7 +12,7 @@ #include "linalg.hpp" #include "macros.hpp" -#include "quest/include/quest.h" +#include "quest.h" #include #include diff --git a/tests/utils/compare.hpp b/tests/utils/compare.hpp index e8e8e9fd9..028b72020 100644 --- a/tests/utils/compare.hpp +++ b/tests/utils/compare.hpp @@ -13,7 +13,7 @@ #ifndef COMPARE_HPP #define COMPARE_HPP -#include "quest/include/quest.h" +#include "quest.h" #include "qvector.hpp" #include "qmatrix.hpp" diff --git a/tests/utils/convert.cpp b/tests/utils/convert.cpp index b5bea9429..7d425d50b 100644 --- a/tests/utils/convert.cpp +++ b/tests/utils/convert.cpp @@ -12,7 +12,7 @@ #include "macros.hpp" #include "lists.hpp" -#include "quest/include/quest.h" +#include "quest.h" #include using std::is_same_v; diff --git a/tests/utils/convert.hpp b/tests/utils/convert.hpp index 1d170e432..6d5b4167c 100644 --- a/tests/utils/convert.hpp +++ b/tests/utils/convert.hpp @@ -13,7 +13,7 @@ #ifndef CONVERT_HPP #define CONVERT_HPP -#include "quest/include/quest.h" +#include "quest.h" #include "qvector.hpp" #include "qmatrix.hpp" diff --git a/tests/utils/lists.cpp b/tests/utils/lists.cpp index a3760ad00..aa20f34db 100644 --- a/tests/utils/lists.cpp +++ b/tests/utils/lists.cpp @@ -8,7 +8,7 @@ #include #include -#include "quest/include/quest.h" +#include "quest.h" #include "lists.hpp" #include "macros.hpp" diff --git a/tests/utils/lists.hpp b/tests/utils/lists.hpp index 4c37b9d80..082fd70ba 100644 --- a/tests/utils/lists.hpp +++ b/tests/utils/lists.hpp @@ -13,7 +13,7 @@ #include -#include "quest/include/quest.h" +#include "quest.h" #include #include diff --git a/tests/utils/measure.cpp b/tests/utils/measure.cpp index 41161675e..1d4246b60 100644 --- a/tests/utils/measure.cpp +++ b/tests/utils/measure.cpp @@ -6,7 +6,7 @@ * @author Tyson Jones */ -#include "quest/include/quest.h" +#include "quest.h" #include "qvector.hpp" #include "qmatrix.hpp" diff --git a/tests/utils/measure.hpp b/tests/utils/measure.hpp index f6061b32e..dd0716db4 100644 --- a/tests/utils/measure.hpp +++ b/tests/utils/measure.hpp @@ -13,7 +13,7 @@ #ifndef MEASURE_HPP #define MEASURE_HPP -#include "quest/include/quest.h" +#include "quest.h" #include "qvector.hpp" #include "qmatrix.hpp" diff --git a/tests/utils/qmatrix.hpp b/tests/utils/qmatrix.hpp index 0fadce493..a34d4322a 100644 --- a/tests/utils/qmatrix.hpp +++ b/tests/utils/qmatrix.hpp @@ -13,7 +13,7 @@ #ifndef QMATRIX_HPP #define QMATRIX_HPP -#include "quest/include/quest.h" +#include "quest.h" #include "qvector.hpp" #include diff --git a/tests/utils/qvector.hpp b/tests/utils/qvector.hpp index 90c24adc5..889f32a46 100644 --- a/tests/utils/qvector.hpp +++ b/tests/utils/qvector.hpp @@ -12,7 +12,7 @@ #ifndef QVECTOR_HPP #define QVECTOR_HPP -#include "quest/include/quest.h" +#include "quest.h" #include "macros.hpp" #include diff --git a/tests/utils/random.cpp b/tests/utils/random.cpp index b2cae350f..65d087518 100644 --- a/tests/utils/random.cpp +++ b/tests/utils/random.cpp @@ -15,7 +15,7 @@ #include "linalg.hpp" #include "lists.hpp" #include "random.hpp" -#include "quest/include/quest.h" +#include "quest.h" #include #include diff --git a/tests/utils/random.hpp b/tests/utils/random.hpp index 0c7261572..cbe6f63c2 100644 --- a/tests/utils/random.hpp +++ b/tests/utils/random.hpp @@ -17,7 +17,7 @@ #include "macros.hpp" #include "linalg.hpp" #include "lists.hpp" -#include "quest/include/quest.h" +#include "quest.h" #include using std::vector; From f11fb9511bb29b54ae3e60360648ccc39456613e Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Thu, 8 May 2025 21:25:01 +0200 Subject: [PATCH 07/12] added Luc Jualmes to authorlist --- AUTHORS.txt | 2 ++ CMakeLists.txt | 1 + README.md | 1 + cmake/QuESTConfig.cmake.in | 1 + quest/include/CMakeLists.txt | 1 + quest/include/quest.h.in | 2 ++ 6 files changed, 8 insertions(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index e77ee6d60..8089802f5 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -44,6 +44,8 @@ Dr Ian Bush [consultant] HPC External contributors: +Luc Jaulmes + patched v4's install process using CMake Jakub Adamski optimised distributed communication by sending max-size messages asynchronously Bruno Villasenor Alvarez on behalf of AMD diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b2cc5694..69acf74ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ # @author Oliver Thomson Brown # @author Erich Essmann (patches including MSVC support) # @author Tyson Jones (patches including clang multithreading) +# @author Luc Jaulmes (patching install) # # Contributions to previous builds from: # - Ania Brown diff --git a/README.md b/README.md index 75c9f41f6..bab2d2ff6 100644 --- a/README.md +++ b/README.md @@ -257,6 +257,7 @@ See the [docs](docs/README.md) for enabling acceleration and running the unit te In addition to QuEST's [authors](AUTHORS.txt), we sincerely thank the following external contributors to QuEST. +- [Luc Jaulmes](https://github.com/lucjaulmes) for patching v4's CMake installation. - [Jakub Adamski](https://github.com/jjacobx) for optimising distributed communication of max-size messages. - [Bruno Villasenor Alvarez](https://github.com/bvillasen) of [AMD](https://www.amd.com/en.html) for porting the v3 GPU backend to [HIP](https://github.com/ROCm-Developer-Tools/HIP), for compatibility with AMD GPUs. - [HQS Quantum simulations](https://quantumsimulations.de/) for prototyping v3 `mixDamping`. diff --git a/cmake/QuESTConfig.cmake.in b/cmake/QuESTConfig.cmake.in index c41c91aa1..5f112d9a4 100644 --- a/cmake/QuESTConfig.cmake.in +++ b/cmake/QuESTConfig.cmake.in @@ -1,4 +1,5 @@ # @author Erich Essmann +# @author Luc Jaulmes (patched use of LIB_NAME) @PACKAGE_INIT@ include("${CMAKE_CURRENT_LIST_DIR}/@LIB_NAME@Targets.cmake") diff --git a/quest/include/CMakeLists.txt b/quest/include/CMakeLists.txt index aec6285ea..86a542dc5 100644 --- a/quest/include/CMakeLists.txt +++ b/quest/include/CMakeLists.txt @@ -1,4 +1,5 @@ # @author Oliver Thomson Brown # @author Erich Essmann +# @author Luc Jaulmes (using config file) configure_file(quest.h.in "${CMAKE_BINARY_DIR}/include/quest.h" @ONLY) diff --git a/quest/include/quest.h.in b/quest/include/quest.h.in index 383b42c04..4ba420478 100644 --- a/quest/include/quest.h.in +++ b/quest/include/quest.h.in @@ -7,6 +7,7 @@ * deprecated v3 API, before including this header. * * @author Tyson Jones + * @author Luc Jaulmes (patching CMake install) * * @defgroup api 📋 API */ @@ -30,6 +31,7 @@ #define QUEST_H +// bind compile settings to installed exec #if !@MULTI_LIB_HEADERS@ #cmakedefine FLOAT_PRECISION @FLOAT_PRECISION@ #cmakedefine01 COMPILE_MPI From c47422633b62a5e46f0b916afffb24283e1267e7 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Thu, 22 May 2025 20:13:02 +0200 Subject: [PATCH 08/12] updated doc (#621) including - removing references to defunct `invalidQuESTInputError` - essential doc needed to disambiguate function conventions (like relationship between function parameters and effected operation phases) - renamed Doxygen keyword `@equivalent` to `@equivalences` - ... `@notvalidated` to `@notyetvalidated` - ... `@notdoced` to `@notyetdoced` - ... `@nottested` to `@notyettested` - changed some `@cpponly` functions into new `@cppvectoroverload`, and then hid the latter - added links from doc to the example PR - linked `C++`-overload doc to corresponding `C` function (using `@see`) --- docs/architecture.md | 4 + docs/contributing.md | 4 + docs/launch.md | 2 +- quest/include/calculations.h | 117 +-- quest/include/channels.h | 242 +++-- quest/include/debug.h | 57 +- quest/include/decoherence.h | 339 ++++++- quest/include/environment.h | 28 +- quest/include/initialisations.h | 126 +-- quest/include/matrices.h | 562 +++++++++--- quest/include/modes.h | 6 +- quest/include/operations.h | 1472 ++++++++++++++++++++++--------- quest/include/paulis.h | 183 +++- quest/include/precision.h | 12 +- quest/include/qureg.h | 342 ++++++- quest/include/types.h | 38 +- quest/src/core/errors.cpp | 14 +- utils/docs/Doxyfile | 16 +- utils/docs/latex/commands.tex | 1 + 19 files changed, 2656 insertions(+), 909 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index 1ad8f3a40..9da920f2a 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -7,6 +7,10 @@ @author Tyson Jones --> +> [!TIP] +> See [PR #615](https://github.com/QuEST-Kit/QuEST/pull/615) for an illustration of integrating +> new functions into the QuEST software architecture. + 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. 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. diff --git a/docs/contributing.md b/docs/contributing.md index cdeb61d67..bd8ce8221 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -13,3 +13,7 @@ In the meantime, feel free to open an issue, a discussion or a pull request, or reach out to `tyson.jones.input@gmail.com`. + +> [!TIP] +> See [PR #615](https://github.com/QuEST-Kit/QuEST/pull/615) for an illustration of integrating +> new functions into the QuEST software architecture. diff --git a/docs/launch.md b/docs/launch.md index 0053e0160..aadd02ca7 100644 --- a/docs/launch.md +++ b/docs/launch.md @@ -595,7 +595,7 @@ For convenience however, we offer some example [SLURM](https://slurm.schedmd.com #SBATCH --nodes=4 #SBATCH --ntasks-per-node=1 #SBATCH --cpus-per-task=8 -OMP_NUM_THREADS=8 mpirun ./myexec +OMP_NUM_THREADS=8 srun ./myexec ``` 1 machine with 4 local GPUs: diff --git a/quest/include/calculations.h b/quest/include/calculations.h index 54ff5ed9b..3d721b573 100644 --- a/quest/include/calculations.h +++ b/quest/include/calculations.h @@ -69,15 +69,17 @@ extern "C" { * which case the imaginary component of the above expression is neglected. * The full complex value can be obtained using calcExpecNonHermitianPauliStrSum(). * - * @equivalence + * @equivalences * - When @p str is general, this function is equivalent to calling calcExpecPauliStrSum() with a * PauliStrSum composed of only a single PauliStr term and a unity coefficient. * - When @p str @f$ = \id^\otimes @f$, the output is equivalent to that of calcTotalProb(). * * @myexample * ``` - Qureg qureg = createQureg(4); - PauliStr str = getPauliStr("XYZ"); + Qureg qureg = createQureg(10); + initRandomPureState(qureg); + + PauliStr str = getInlinePauliStr("XYZ", {0,2,3}); qreal expec = calcExpecPauliStr(qureg, str); reportScalar("expec", expec); @@ -89,11 +91,11 @@ extern "C" { * @param[in] qureg the reference state. * @param[in] str the observable operator. * @returns The real component of the expectation value. - * @throws invalidQuESTInputError() + * @throws @validationerror * - if @p qureg is uninitialised. * - if @p str contains a (non-identity) Pauli upon a higher-index qubit than exists in @p qureg. * - if the output (with unreturned imaginary component) is not approximately real. - * @notvalidated + * @notyetvalidated * @author Tyson Jones */ qreal calcExpecPauliStr(Qureg qureg, PauliStr str); @@ -125,7 +127,7 @@ qreal calcExpecPauliStr(Qureg qureg, PauliStr str); * Hermiticity validation is relaxed and/or @p qureg is an unnormalised density matrix. * The full complex value can be obtained using calcExpecNonHermitianPauliStrSum(). * - * @equivalence + * @equivalences * - This function is mathematically equivalent to (albeit faster than) calling calcExpecPauliStr() upon * each constituent @p PauliStr within @p sum, weighting each by its corresponding coefficient, and * summing the outputs. @@ -145,15 +147,16 @@ qreal calcExpecPauliStr(Qureg qureg, PauliStr str); qreal expec = calcExpecPauliStrSum(qureg, sum); reportScalar("expec", expec); * ``` + * * @param[in] qureg the reference state. * @param[in] sum the observable operator. * @returns The real component of the expectation value. - * @throws invalidQuESTInputError() + * @throws @validationerror * - if @p qureg or @p sum are uninitialised. * - if any PauliStr in @p sum targets a higher-index qubit than exists in @p qureg. * - if @p sum is not approximately Hermitian. * - if the output (with unreturned imaginary component) is not approximately real. -* @notvalidated +* @notyetvalidated * @see * - calcExpecNonHermitianPauliStrSum() * - calcExpecFullStateDiagMatr() @@ -162,13 +165,13 @@ qreal calcExpecPauliStr(Qureg qureg, PauliStr str); qreal calcExpecPauliStrSum(Qureg qureg, PauliStrSum sum); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qreal calcExpecFullStateDiagMatr(Qureg qureg, FullStateDiagMatr matr); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qreal calcExpecFullStateDiagMatrPower(Qureg qureg, FullStateDiagMatr matr, qreal exponent); @@ -183,23 +186,23 @@ qreal calcExpecFullStateDiagMatrPower(Qureg qureg, FullStateDiagMatr matr, qreal */ -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qreal calcProbOfBasisState(Qureg qureg, qindex index); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qreal calcProbOfQubitOutcome(Qureg qureg, int qubit, int outcome); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qreal calcProbOfMultiQubitOutcome(Qureg qureg, int* qubits, int* outcomes, int numQubits); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void calcProbsOfAllMultiQubitOutcomes(qreal* outcomeProbs, Qureg qureg, int* qubits, int numQubits); @@ -214,13 +217,13 @@ void calcProbsOfAllMultiQubitOutcomes(qreal* outcomeProbs, Qureg qureg, int* qub */ -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qreal calcTotalProb(Qureg qureg); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qreal calcPurity(Qureg qureg); @@ -235,12 +238,12 @@ qreal calcPurity(Qureg qureg); */ -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qreal calcFidelity(Qureg qureg, Qureg other); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qreal calcDistance(Qureg qureg1, Qureg qureg2); @@ -255,13 +258,13 @@ qreal calcDistance(Qureg qureg1, Qureg qureg2); */ -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated Qureg calcPartialTrace(Qureg qureg, int* traceOutQubits, int numTraceQubits); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated Qureg calcReducedDensityMatrix(Qureg qureg, int* retainQubits, int numRetainQubits); @@ -292,26 +295,26 @@ Qureg calcReducedDensityMatrix(Qureg qureg, int* retainQubits, int numRetainQubi /// @ingroup calc_comparisons -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qcomp calcInnerProduct(Qureg qureg1, Qureg qureg2); /// @ingroup calc_expec -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qcomp calcExpecNonHermitianPauliStrSum(Qureg qureg, PauliStrSum sum); /// @ingroup calc_expec -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qcomp calcExpecNonHermitianFullStateDiagMatr(Qureg qureg, FullStateDiagMatr matr); /// @ingroup calc_expec -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qcomp calcExpecNonHermitianFullStateDiagMatrPower(Qureg qureg, FullStateDiagMatr matrix, qcomp exponent); @@ -330,34 +333,38 @@ qcomp calcExpecNonHermitianFullStateDiagMatrPower(Qureg qureg, FullStateDiagMatr /// @ingroup calc_prob -/// @nottested -/// @notdoced -/// @notvalidated -/// @cpponly +/// @notyettested +/// @notyetdoced +/// @notyetvalidated +/// @cppoverload +/// @see calcProbOfMultiQubitOutcome() qreal calcProbOfMultiQubitOutcome(Qureg qureg, std::vector qubits, std::vector outcomes); /// @ingroup calc_prob -/// @nottested -/// @notdoced -/// @notvalidated +/// @notyettested +/// @notyetdoced +/// @notyetvalidated /// @cpponly +/// @see calcProbsOfAllMultiQubitOutcomes() std::vector calcProbsOfAllMultiQubitOutcomes(Qureg qureg, std::vector qubits); /// @ingroup calc_partialtrace -/// @nottested -/// @notdoced -/// @notvalidated -/// @cpponly +/// @notyettested +/// @notyetdoced +/// @notyetvalidated +/// @cppoverload +/// @see calcPartialTrace() Qureg calcPartialTrace(Qureg qureg, std::vector traceOutQubits); /// @ingroup calc_partialtrace -/// @nottested -/// @notdoced -/// @notvalidated -/// @cpponly +/// @notyettested +/// @notyetdoced +/// @notyetvalidated +/// @cppoverload +/// @see calcReducedDensityMatrix() Qureg calcReducedDensityMatrix(Qureg qureg, std::vector retainQubits); diff --git a/quest/include/channels.h b/quest/include/channels.h index 10d28f9aa..c0f5433f6 100644 --- a/quest/include/channels.h +++ b/quest/include/channels.h @@ -70,7 +70,7 @@ */ -/// @notdoced +/// @notyetdoced typedef struct { int numQubits; @@ -97,7 +97,7 @@ typedef struct { } SuperOp; -/// @notdoced +/// @notyetdoced typedef struct { int numQubits; @@ -176,45 +176,75 @@ extern "C" { #endif - /// @ingroup channels_create - /// @notdoced + /** @ingroup channels_create + * @notyetdoced + * + * @see + * - createInlineKrausMap + * - createSuperOp() + * - setKrausMap() + * - setInlineKrausMap + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.c) or + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.cpp) examples + */ KrausMap createKrausMap(int numQubits, int numOperators); - /// @ingroup channels_sync - /// @notdoced + /** @ingroup channels_sync + * @notyetdoced + * + * @see + * - setKrausMap() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.c) or + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.cpp) examples + */ void syncKrausMap(KrausMap map); /// @ingroup channels_destroy - /// @notdoced + /// @notyetdoced void destroyKrausMap(KrausMap map); /// @ingroup channels_reporters - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested void reportKrausMap(KrausMap map); - /// @ingroup channels_create - /// @notdoced + /** @ingroup channels_create + * @notyetdoced + * + * @see + * - createInlineSuperOp() + * - createKrausMap() + * - setSuperOp() + * - setInlineSuperOp() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.c) or + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.cpp) examples + */ SuperOp createSuperOp(int numQubits); - /// @ingroup channels_sync - /// @notdoced + /** @ingroup channels_sync + * @notyetdoced + * + * @see + * - setSuperOp() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.c) or + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.cpp) examples + */ void syncSuperOp(SuperOp op); /// @ingroup channels_destroy - /// @notdoced + /// @notyetdoced void destroySuperOp(SuperOp op); /// @ingroup channels_reporters - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested void reportSuperOp(SuperOp op); @@ -240,13 +270,27 @@ extern "C" { #endif - /// @ingroup channels_setters - /// @notdoced + /** @ingroup channels_setters + * @notyetdoced + * + * @see + * - setInlineKrausMap() + * - syncKrausMap() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.c) or + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.cpp) examples + */ void setKrausMap(KrausMap map, qcomp*** matrices); - /// @ingroup channels_setters - /// @notdoced + /** @ingroup channels_setters + * @notyetdoced + * + * @see + * - setInlineSuperOp() + * - syncSuperOp() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.c) or + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.cpp) examples + */ void setSuperOp(SuperOp op, qcomp** matrix); @@ -278,15 +322,25 @@ extern "C" { // C++ overloads to accept vectors, which also enables vector initialiser literals - /// @ingroup channels_setters - /// @notdoced - /// @cpponly + /** @ingroup channels_setters + * @notyetdoced + * @cpponly + * + * @see + * - setInlineKrausMap() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.cpp) examples + */ void setKrausMap(KrausMap map, std::vector>> matrices); - /// @ingroup channels_setters - /// @notdoced - /// @cpponly + /** @ingroup channels_setters + * @notyetdoced + * @cpponly + * + * @see + * - setInlineSuperOp() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.cpp) examples + */ void setSuperOp(SuperOp op, std::vector> matrix); @@ -359,18 +413,31 @@ extern "C" { // spoofing macros as functions #if 0 - /// @ingroup channels_setters - /// @notdoced - /// @conly - /// @macrodoc + + /** @ingroup channels_setters + * @notyetdoced + * @conly + * @macrodoc + * + * @see + * - setInlineKrausMap() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.c) examples + */ void setKrausMap(KrausMap map, qcomp matrices[map.numMatrices][map.numRows][map.numRows]); - /// @ingroup channels_setters - /// @notdoced - /// @conly - /// @macrodoc + + /** @ingroup channels_setters + * @notyetdoced + * @conly + * @macrodoc + * + * @see + * - setInlineSuperOp() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.c) examples + */ void setSuperOp(SuperOp op, qcomp matrix[op.numRows][op.numRows]); + #endif @@ -404,15 +471,27 @@ extern "C" { // validate that they match the struct dimensions (which requires validating the structs). - /// @ingroup channels_setters - /// @notdoced - /// @cpponly + /** @ingroup channels_setters + * @notyetdoced + * @cpponly + * + * @see + * - setKrausMap() + * - syncKrausMap() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.cpp) examples + */ void setInlineKrausMap(KrausMap map, int numQb, int numOps, std::vector>> matrices); - /// @ingroup channels_setters - /// @notdoced - /// @cpponly + /** @ingroup channels_setters + * @notyetdoced + * @cpponly + * + * @see + * - setSuperOp() + * - syncSuperOp() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.cpp) examples + */ void setInlineSuperOp(SuperOp op, int numQb, std::vector> matrix); @@ -451,7 +530,6 @@ extern "C" { #define setInlineKrausMap(map, numQb, numOps, ...) \ _setInlineKrausMap((map), (numQb), (numOps), (qcomp[(numOps)][1<<(numQb)][1<<(numQb)]) __VA_ARGS__) - /// @neverdoced #define setInlineSuperOp(matr, numQb, ...) \ _setInlineSuperOp((matr), (numQb), (qcomp[1<<(2*(numQb))][1<<(2*(numQb))]) __VA_ARGS__) @@ -459,16 +537,31 @@ extern "C" { // spoofing macros as functions #if 0 - /// @ingroup channels_setters - /// @notdoced - /// @macrodoc + + /** @ingroup channels_setters + * @notyetdoced + * @macrodoc + * + * @see + * - setKrausMap() + * - syncKrausMap() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.c) examples + */ void setInlineKrausMap(KrausMap map, int numQb, int numOps, {{{ matrices }}}); - /// @ingroup channels_setters - /// @notdoced - /// @macrodoc + + /** @ingroup channels_setters + * @notyetdoced + * @macrodoc + * + * @see + * - setSuperOp() + * - syncSuperOp() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.c) examples + */ void setInlineSuperOp(SuperOp op, int numQb, {{ matrix }}); + #endif #else @@ -494,15 +587,29 @@ extern "C" { // C++ accepts vector initialiser lists - /// @ingroup channels_create - /// @notdoced - /// @cpponly + /** @ingroup channels_create + * @notyetdoced + * @cpponly + * + * @see + * - createKrausMap() + * - setKrausMap() + * - syncKrausMap() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.cpp) examples + */ KrausMap createInlineKrausMap(int numQubits, int numOperators, std::vector>> matrices); - /// @ingroup channels_create - /// @notdoced - /// @cpponly + /** @ingroup channels_create + * @notyetdoced + * @cpponly + * + * @see + * - createSuperOp() + * - setSuperOp() + * - syncSuperOp() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.cpp) examples + */ SuperOp createInlineSuperOp(int numQubits, std::vector> matrix); @@ -550,16 +657,33 @@ extern "C" { // spoofing macros as functions #if 0 - /// @ingroup channels_create - /// @notdoced - /// @macrodoc + + /** @ingroup channels_create + * @notyetdoced + * @macrodoc + * + * @see + * - createKrausMap() + * - setKrausMap() + * - syncKrausMap() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_krausmaps.c) examples + */ KrausMap createInlineKrausMap(int numQb, int numOps, {{{ matrices }}}); - /// @ingroup channels_create - /// @notdoced - /// @macrodoc + + /** @ingroup channels_create + * @notyetdoced + * @macrodoc + * + * @see + * - createSuperOp() + * - setSuperOp() + * - syncSuperOp() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_superoperators.c) examples + */ SuperOp createInlineSuperOp(int numQb, {{ matrix }}); + #endif #else diff --git a/quest/include/debug.h b/quest/include/debug.h index fbe34e3e1..3168e023b 100644 --- a/quest/include/debug.h +++ b/quest/include/debug.h @@ -42,19 +42,19 @@ extern "C" { */ -/// @notdoced +/// @notyetdoced void setSeeds(unsigned* seeds, int numSeeds); -/// @notdoced +/// @notyetdoced void setSeedsToDefault(); -/// @notdoced +/// @notyetdoced void getSeeds(unsigned* seeds); -/// @notdoced +/// @notyetdoced int getNumSeeds(); @@ -73,27 +73,32 @@ int getNumSeeds(); */ -/// @notdoced +/** @notyetdoced + * + * @see + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/setting_errorhandler.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/setting_errorhandler.cpp) examples + */ void setInputErrorHandler(void (*callback)(const char* func, const char* msg)); -/// @notdoced +/// @notyetdoced void setValidationOn(); -/// @notdoced +/// @notyetdoced void setValidationOff(); -/// @notdoced +/// @notyetdoced void setValidationEpsilonToDefault(); -/// @notdoced +/// @notyetdoced void setValidationEpsilon(qreal eps); -/// @notdoced +/// @notyetdoced qreal getValidationEpsilon(); @@ -108,16 +113,20 @@ qreal getValidationEpsilon(); */ -/// @notdoced -/// @nottested +/// @notyetdoced +/// @notyettested void setMaxNumReportedItems(qindex numRows, qindex numCols); -/// @notdoced +/** @notyetdoced + * > This function does not affect the significant figures in printed memory sizes + * > (e.g. `5.32 KiB`) which is always shown with three significant figures + * > (or four when in bytes, e.g. `1023 bytes`). + */ void setMaxNumReportedSigFigs(int numSigFigs); -/// @notdoced +/// @notyetdoced void setNumReportedNewlines(int numNewlines); @@ -164,11 +173,11 @@ void setReportedPauliStrStyle(int style); */ -/// @notdoced +/// @notyetdoced qindex getGpuCacheSize(); -/// @notdoced +/// @notyetdoced void clearGpuCache(); @@ -183,8 +192,8 @@ void clearGpuCache(); */ -/// @notdoced -/// @nottested +/// @notyetdoced +/// @notyettested void getEnvironmentString(char str[200]); @@ -213,16 +222,18 @@ void getEnvironmentString(char str[200]); /// @ingroup debug_seed -/// @nottested -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetdoced +/// @cppvectoroverload +/// @see setSeeds() void setSeeds(std::vector seeds); /// @ingroup debug_seed -/// @nottested -/// @notdoced +/// @notyettested +/// @notyetdoced /// @cpponly +/// @see getSeeds() std::vector getSeeds(); diff --git a/quest/include/decoherence.h b/quest/include/decoherence.h index c6b55d6ab..689ec640f 100644 --- a/quest/include/decoherence.h +++ b/quest/include/decoherence.h @@ -28,40 +28,313 @@ extern "C" { #endif -/// @notdoced -/// @notvalidated -void mixDephasing(Qureg qureg, int qubit, qreal prob); -/// @notdoced -/// @notvalidated -void mixTwoQubitDephasing(Qureg qureg, int qubit1, int qubit2, qreal prob); +/** @notyetdoced + * + * @formulae + * Let @f$ \dmrho = @f$ @p qureg, @f$ p = @f$ @p prob and @f$ t = @f$ @p target. + * + * This function effects + * @f[ + \dmrho + \;\rightarrow\; + (1 - p) \, \dmrho + \,+\, + p \, \hat{Z}_t \,\dmrho\, \hat{Z}_t. + * @f] + * + * @equivalences + * This function is equivalent to (but much faster than): + * - mixPaulis() with a zero probability for the @f$\hat{X}@f$ and @f$\hat{Y}@f$ components. + * ``` + mixPaulis(qureg, target, 0, 0, prob); + * ``` + * - mixKrausMap() with (scaled) @f$\hat{\id}@f$ and @f$\hat{Z}@f$ Kraus operators. + * ``` + qreal a = sqrt(1-prob); + qreal b = sqrt(prob); + + KrausMap map = createInlineKrausMap(1, 2, { + {{a,0},{0, a}}, // a * I + {{b,0},{0,-b}} // b * Z + }); + + mixKrausMap(qureg, &target, 1, map); + * ``` + * - mixQureg() with a duplicated Qureg modified under applyPauliZ(). + * ``` + Qureg clone = createCloneQureg(qureg); + applyPauliZ(clone); + mixQureg(qureg, other, prob); + * ``` + * + * @notyetvalidated + */ +void mixDephasing(Qureg qureg, int target, qreal prob); + -/// @notdoced -/// @notvalidated -void mixDepolarising(Qureg qureg, int qubit, qreal prob); +/** @notyetdoced + * + * @formulae + * Let @f$ \dmrho = @f$ @p qureg, @f$ p = @f$ @p prob, @f$ t_1 = @f$ @p target1 and @f$ t_2 = @f$ @p target2. + * + * This function effects + * @f[ + \dmrho + \;\rightarrow\; + (1 - p) \, \dmrho + \,+\, + \frac{p}{3} \left( + \hat{Z}_{t_1} \dmrho \hat{Z}_{t_1} + \,+\, + \hat{Z}_{t_1} \dmrho \hat{Z}_{t_1} + \,+\, + \hat{Z}_{t_1} \hat{Z}_{t_2} \dmrho \hat{Z}_{t_1} \hat{Z}_{t_2} + \right). + * @f] + * + * @equivalences + * This function is equivalent to (but much faster than): + * - mixKrausMap() with (scaled) @f$\hat{\id}\otimes\hat{\id}@f$, @f$\hat{\id}\otimes\hat{Z}@f$, + * @f$\hat{Z}\otimes\hat{\id}@f$ and @f$\hat{Z}\otimes\hat{Z}@f$ Kraus operators. + * ``` + qreal a = sqrt(1-prob); + qreal b = sqrt(prob/3); -/// @notdoced -/// @notvalidated -void mixTwoQubitDepolarising(Qureg qureg, int qubit1, int qubit2, qreal prob); + KrausMap map = createInlineKrausMap(2, 4, { + {{a,0,0,0},{0, a,0,0},{0,0, a,0},{0,0,0, a}}, // a * II + {{b,0,0,0},{0,-b,0,0},{0,0, b,0},{0,0,0,-b}}, // b * IZ + {{b,0,0,0},{0, b,0,0},{0,0,-b,0},{0,0,0,-b}}, // b * ZI + {{b,0,0,0},{0,-b,0,0},{0,0,-b,0},{0,0,0, b}} // b * ZZ + }); + + int targets[] = {target1, target2}; + mixKrausMap(qureg, targets, 2, map); + * ``` + * + * @notyetvalidated + */ +void mixTwoQubitDephasing(Qureg qureg, int target1, int target2, qreal prob); -/// @notdoced -/// @notvalidated -void mixDamping(Qureg qureg, int qubit, qreal prob); -/// @notdoced -/// @notvalidated -void mixPaulis(Qureg qureg, int qubit, qreal probX, qreal probY, qreal probZ); +/** @notyetdoced + * + * @formulae + * Let @f$ \dmrho = @f$ @p qureg, @f$ p = @f$ @p prob and @f$ t = @f$ @p target. + * + * This function effects + * @f[ + \dmrho \;\rightarrow\; + (1 - p) \, \dmrho \,+\, \frac{p}{3} \left( + \hat{X}_t \dmrho \hat{X}_t \,+\, + \hat{Y}_t \dmrho \hat{Y}_t \,+\, + \hat{Z}_t \dmrho \hat{Z}_t + \right). + * @f] + * + * @equivalences + * This function is equivalent to (but much faster than): + * - mixPaulis() with a uniform probability. + * ``` + mixPaulis(qureg, target, prob/3, prob/3, prob/3); + * ``` + * - mixKrausMap() with (scaled) @f$\hat{\id}@f$, @f$\hat{X}@f$, @f$\hat{Y}@f$ and @f$\hat{Z}@f$ Kraus operators. + * ``` + qreal a = sqrt(1-prob); + qreal b = sqrt(prob/3); + + KrausMap map = createInlineKrausMap(1, 4, { + {{a,0},{0, a}}, // a * I + {{0,b},{b, 0}}, // b * X + {{b,0},{0,-b}} // b * Z + {{0,-1i*b},{1i*b,0}}, // b * Y + }); + + mixKrausMap(qureg, &target, 1, map); + * ``` + * + * @notyetvalidated + */ +void mixDepolarising(Qureg qureg, int target, qreal prob); + + +/** @notyetdoced + * + * @formulae + * Let @f$ \dmrho = @f$ @p qureg, @f$ p = @f$ @p prob, @f$ t_1 = @f$ @p target1 and @f$ t_2 = @f$ @p target2. + * + * This function effects: + * @f[ + \dmrho \; \rightarrow \; + (1 - p) \dmrho + + + \frac{p}{15} \left( + \sum_{\hat{\sigma} \in \{\hat{\id},\hat{X},\hat{Y},\hat{Z}\}} + \sum_{\hat{\sigma}' \in \{\hat{\id},\hat{X},\hat{Y},\hat{Z}\}} + \hat{\sigma}_{t_1} \hat{\sigma}_{t_2}' + \; \dmrho \; + \hat{\sigma}_{t_1} \hat{\sigma}_{t_2}' + \right) + - \frac{p}{15} \hat{\id}_{t_1} \hat{\id}_{t_2} \dmrho \hat{\id}_{t_1} \hat{\id}_{t_2}, + * @f] + * + * or verbosely: + * + * @f[ + \dmrho \; \rightarrow \; + (1 - p) \, \rho + \frac{p}{15} \; + \left( + \begin{gathered} + \hat{X}_{t_1} \, \rho \, \hat{X}_{t_1} + + \hat{Y}_{t_1} \, \rho \, \hat{Y}_{t_1} + + \hat{Z}_{t_1} \, \rho \, \hat{Z}_{t_1} + + \\ + \hat{X}_{t_2} \, \rho \, \hat{X}_{t_2} + + \hat{Y}_{t_2} \, \rho \, \hat{Y}_{t_2} + + \hat{Z}_{t_2} \, \rho \, \hat{Z}_{t_2} + + \\ + \hat{X}_{t_1} \hat{X}_{t_2} \, \rho \, \hat{X}_{t_1} \hat{X}_{t_2} + + \hat{Y}_{t_1} \hat{Y}_{t_2} \, \rho \, \hat{Y}_{t_1} \hat{Y}_{t_2} + + \hat{Z}_{t_1} \hat{Z}_{t_2} \, \rho \, \hat{Z}_{t_1} \hat{Z}_{t_2} + + \\ + \hat{X}_{t_1} \hat{Y}_{t_2} \, \rho \, \hat{X}_{t_1} \hat{Y}_{t_2} + + \hat{Y}_{t_1} \hat{Z}_{t_2} \, \rho \, \hat{Y}_{t_1} \hat{Z}_{t_2} + + \hat{Z}_{t_1} \hat{X}_{t_2} \, \rho \, \hat{Z}_{t_1} \hat{X}_{t_2} + + \\ + \hat{X}_{t_1} \hat{Z}_{t_2} \, \rho \, \hat{X}_{t_1} \hat{Z}_{t_2} + + \hat{Y}_{t_1} \hat{X}_{t_2} \, \rho \, \hat{Y}_{t_1} \hat{Z}_{t_2} + + \hat{Z}_{t_1} \hat{Y}_{t_2} \, \rho \, \hat{Z}_{t_1} \hat{Y}_{t_2} + \end{gathered} + \right). + * @f] + * + * @equivalences + * This function is equivalent to (but much faster than): + * - mixKrausMap() with Kraus operators containing every possible tensor product + * of two Pauli matrices, all scaled by @f$ (p/15)^{1/2} @f$, _except_ for + * @f$ \hat{\id} \otimes \hat{\id} @f$ which is scaled by @f$ (1-16p/15)^{1/2} @f$. + * + * @notyetvalidated + */ +void mixTwoQubitDepolarising(Qureg qureg, int target1, int target2, qreal prob); -/// @notdoced -/// @notvalidated + +/** @notyetdoced + * + * @formulae + * Let @f$ \dmrho = @f$ @p qureg, @f$ p = @f$ @p prob and @f$ t = @f$ @p target. + * + * This function effects + * @f[ + \dmrho \; \rightarrow \; + \hat{K}_t^{(1)} \dmrho \, {\hat{K}_t^{(2)}}^\dagger + \,+\, + \hat{K}_t^{(2)} \dmrho \, {\hat{K}_t^{(2)}}^\dagger + * @f] + * where @f$ \hat{K}^{(1)} @f$ and @f$ \hat{K}^{(2)} @f$ are one-qubit Kraus operators + * @f[ + \hat{K}^{(1)} = \begin{pmatrix} 1 & 0 \\ 0 & \sqrt{1-p} \end{pmatrix}, + \;\; + \hat{K}^{(1)} = \begin{pmatrix} 0 & \sqrt{p} \\ 0 & 0 \end{pmatrix}. + * @f] + * + * @equivalences + * This function is equivalent to (but much faster than): + * - mixKrausMap() with the above Kraus operators. + * ``` + KrausMap map = createInlineKrausMap(1, 2, { + {{1,0},{0,sqrt(1-prob)}}, // K1 + {{0,sqrt(p)},{0,0}} // K2 + }); + + mixKrausMap(qureg, &target, 1, map); + * ``` + * + * @notyetvalidated + */ +void mixDamping(Qureg qureg, int target, qreal prob); + + +/** @notyetdoced + * + * @formulae + * Let @f$ \dmrho = @f$ @p qureg, @f$ t = @f$ @p target, and + * @f$ p_x = @f$ @p probX, @f$ p_y = @f$ @p probY, @f$ p_z = @f$ @p probZ. + * + * This function effects + * @f[ + \dmrho \;\rightarrow\; + (1 - p) \, \dmrho + \,+\, + p_x \, \hat{X}_t \dmrho \hat{X}_t + \,+\, + p_y \, \hat{Y}_t \dmrho \hat{Y}_t + \,+\, + p_z \, \hat{Z}_t \dmrho \hat{Z}_t. + * @f] + * + * @equivalences + * This function is equivalent to (but much faster than): + * - mixKrausMap() with (scaled) @f$\hat{\id}@f$, @f$\hat{X}@f$, @f$\hat{Y}@f$ and @f$\hat{Z}@f$ Kraus operators. + * ``` + qreal a = sqrt(1-probX-probY-probZ); + qreal b = sqrt(probX); + qreal c = sqrt(probY); + qreal d = sqrt(probZ); + + KrausMap map = createInlineKrausMap(1, 4, { + {{a,0},{0, a}}, // a * I + {{0,b},{b, 0}}, // b * X + {{d,0},{0,-d}} // d * Z + {{0,-1i*c},{1i*c,0}}, // c * Y + }); + + mixKrausMap(qureg, &target, 1, map); + * ``` + * + * @notyetvalidated + */ +void mixPaulis(Qureg qureg, int target, qreal probX, qreal probY, qreal probZ); + + +/** @notyetdoced + * + * @formulae + * Let @f$ \dmrho_1 = @f$ @p qureg, @f$ \dmrho_2 = @f$ @p other and @f$ p = @f$ @p prob. + * + * This function effects + * @f[ + \dmrho_1 \;\rightarrow \; + (1 - p) \, \dmrho_1 + \,+\, + p \, \dmrho_2. + * @f] + * + * @notyetvalidated + */ void mixQureg(Qureg qureg, Qureg other, qreal prob); -/// @notdoced -/// @notvalidated + +/** @notyetdoced + * + * @formulae + * Let @f$ \dmrho = @f$ @p qureg, @f$ \vec{t} = @f$ @p targets and @f$ \hat{K}^{(i)} @f$ + * denote the @f$i@f$-th Kraus operator in @p map. + * + * This function effects + * @f[ + \dmrho \; \rightarrow \; + \sum\limits_i + \hat{K}_{\vec{t}}^{(i)} \dmrho \, {\hat{K}_{\vec{t}}^{(i)}}^\dagger + * @f] + * + * @notyetvalidated + */ void mixKrausMap(Qureg qureg, int* targets, int numTargets, KrausMap map); -/// @notdoced -/// @notvalidated + +/// @notyetdoced +/// @notyetvalidated void mixSuperOp(Qureg qureg, int* targets, int numTargets, SuperOp superop); @@ -84,16 +357,18 @@ void mixSuperOp(Qureg qureg, int* targets, int numTargets, SuperOp superop); #include -/// @nottested -/// @notdoced -/// @notvalidated -/// @cpponly +/// @notyettested +/// @notyetdoced +/// @notyetvalidated +/// @cppvectoroverload +/// @see mixKrausMap() void mixKrausMap(Qureg qureg, std::vector targets, KrausMap map); -/// @nottested -/// @notdoced -/// @notvalidated -/// @cpponly +/// @notyettested +/// @notyetdoced +/// @notyetvalidated +/// @cppvectoroverload +/// @see mixSuperOp() void mixSuperOp(Qureg qureg, std::vector targets, SuperOp superop); #endif // __cplusplus diff --git a/quest/include/environment.h b/quest/include/environment.h index 3657cf00f..df24ab258 100644 --- a/quest/include/environment.h +++ b/quest/include/environment.h @@ -29,7 +29,7 @@ extern "C" { * local copy of this struct with getQuESTEnv(). */ -/// @notdoced +/// @notyetdoced typedef struct { // deployment mode @@ -44,26 +44,36 @@ typedef struct { } QuESTEnv; -/// @notdoced +/// @notyetdoced void initQuESTEnv(); -/// @notdoced +/** @notyetdoced + * + * @see + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_environments.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_environments.cpp) examples + */ void initCustomQuESTEnv(int useDistrib, int useGpuAccel, int useMultithread); -/// @notdoced +/// @notyetdoced void finalizeQuESTEnv(); -/// @notdoced +/// @notyetdoced void syncQuESTEnv(); -/// @notdoced -/// @nottested +/** @notyetdoced + * @notyettested + * + * @see + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_environments.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_environments.cpp) examples + */ void reportQuESTEnv(); -/// @notdoced +/// @notyetdoced int isQuESTEnvInit(); -/// @notdoced +/// @notyetdoced QuESTEnv getQuESTEnv(); diff --git a/quest/include/initialisations.h b/quest/include/initialisations.h index 716971f6d..06599fdda 100644 --- a/quest/include/initialisations.h +++ b/quest/include/initialisations.h @@ -39,49 +39,49 @@ extern "C" { */ -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void initBlankState(Qureg qureg); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void initZeroState(Qureg qureg); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void initPlusState(Qureg qureg); -/// @notdoced -/// @notvalidated -/// @nottested +/// @notyetdoced +/// @notyetvalidated +/// @notyettested void initPureState(Qureg qureg, Qureg pure); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void initClassicalState(Qureg qureg, qindex stateInd); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void initDebugState(Qureg qureg); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void initArbitraryPureState(Qureg qureg, qcomp* amps); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void initRandomPureState(Qureg qureg); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void initRandomMixedState(Qureg qureg, qindex numPureStates); @@ -96,48 +96,65 @@ void initRandomMixedState(Qureg qureg, qindex numPureStates); */ -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void setQuregAmps(Qureg qureg, qindex startInd, qcomp* amps, qindex numAmps); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void setDensityQuregAmps(Qureg qureg, qindex startRow, qindex startCol, qcomp** amps, qindex numRows, qindex numCols); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void setDensityQuregFlatAmps(Qureg qureg, qindex startInd, qcomp* amps, qindex numAmps); -/// @notdoced -/// @nottested +/// @notyetdoced +/// @notyettested void setQuregToClone(Qureg targetQureg, Qureg copyQureg); -/// @notdoced -/// @nottested +/** @notyetdoced + * @notyettested + * + * @formulae + * + * Let @f$ f_{\text{out}} = @f$ @p facOut, @f$ f_1 = @f$ @p fac1 and @f$ f_2 = @f$ @p fac2. + * Similarly, let @f$ \psi_{\text{out}} = @f$ @p out, @f$ \psi_{1} = @f$ @p qureg1 and @f$ \psi_{2} = @f$ @p qureg2. + * + * This function modifies only @p facOut to become + * @f[ + |\psi_{\text{out}}\rangle \; \rightarrow \; + f_{\text{out}} |\psi_{\text{out}}\rangle \, + \, + f_1 |\psi_1\rangle \, + \, + f_2 |\psi_2\rangle. + * @f] + * + * All factors are unconstrained and are permitted to be zero, and the same @p Qureg can be duplicated among + * all arguments. + */ void setQuregToSuperposition(qcomp facOut, Qureg out, qcomp fac1, Qureg qureg1, qcomp fac2, Qureg qureg2); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qreal setQuregToRenormalized(Qureg qureg); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void setQuregToPauliStrSum(Qureg qureg, PauliStrSum sum); -/// @notdoced -/// @nottested +/// @notyetdoced +/// @notyettested void setQuregToPartialTrace(Qureg out, Qureg in, int* traceOutQubits, int numTraceQubits); -/// @notdoced -/// @nottested +/// @notyetdoced +/// @notyettested void setQuregToReducedDensityMatrix(Qureg out, Qureg in, int* retainQubits, int numRetainQubits); @@ -166,42 +183,47 @@ void setQuregToReducedDensityMatrix(Qureg out, Qureg in, int* retainQubits, int /// @ingroup init_amps -/// @nottested -/// @notdoced -/// @notvalidated +/// @notyettested +/// @notyetdoced +/// @notyetvalidated /// @cpponly +/// @see setQuregAmps() void setQuregAmps(Qureg qureg, qindex startInd, std::vector amps); /// @ingroup init_amps -/// @nottested -/// @notdoced -/// @notvalidated +/// @notyettested +/// @notyetdoced +/// @notyetvalidated /// @cpponly +/// @see setDensityQuregAmps() void setDensityQuregAmps(Qureg qureg, qindex startRow, qindex startCol, std::vector> amps); /// @ingroup init_amps -/// @nottested -/// @notdoced -/// @notvalidated +/// @notyettested +/// @notyetdoced +/// @notyetvalidated /// @cpponly +/// @see setDensityQuregFlatAmps() void setDensityQuregFlatAmps(Qureg qureg, qindex startInd, std::vector amps); /// @ingroup init_amps -/// @nottested -/// @notdoced -/// @notvalidated +/// @notyettested +/// @notyetdoced +/// @notyetvalidated /// @cpponly +/// @see setQuregToPartialTrace() void setQuregToPartialTrace(Qureg out, Qureg in, std::vector traceOutQubits); /// @ingroup init_amps -/// @nottested -/// @notdoced -/// @notvalidated +/// @notyettested +/// @notyetdoced +/// @notyetvalidated /// @cpponly +/// @see setQuregToReducedDensityMatrix() void setQuregToReducedDensityMatrix(Qureg out, Qureg in, std::vector retainQubits); diff --git a/quest/include/matrices.h b/quest/include/matrices.h index 9606c7f0e..8ff4e9ff3 100644 --- a/quest/include/matrices.h +++ b/quest/include/matrices.h @@ -60,7 +60,7 @@ */ -/// @notdoced +/// @notyetdoced typedef struct { int numQubits; @@ -71,7 +71,7 @@ typedef struct { } CompMatr1; -/// @notdoced +/// @notyetdoced typedef struct { int numQubits; @@ -82,7 +82,7 @@ typedef struct { } CompMatr2; -/// @notdoced +/// @notyetdoced typedef struct { // beware that CompMatr instances are sometimes 'spoofed' inside localiser.cpp, @@ -128,7 +128,7 @@ typedef struct { */ -/// @notdoced +/// @notyetdoced typedef struct { int numQubits; @@ -139,7 +139,7 @@ typedef struct { } DiagMatr1; -/// @notdoced +/// @notyetdoced typedef struct { int numQubits; @@ -150,7 +150,7 @@ typedef struct { } DiagMatr2; -/// @notdoced +/// @notyetdoced typedef struct { int numQubits; @@ -187,7 +187,7 @@ typedef struct { */ -/// @notdoced +/// @notyetdoced typedef struct { int numQubits; @@ -306,8 +306,18 @@ extern void _validateNewElemsPtrNotNull(qcomp* ptr, const char* caller); #endif -/// @ingroup matrices_getters -/// @notdoced +/** @ingroup matrices_getters + * @notyetdoced + * + * @see + * - reportCompMatr1() + * - getInlineCompMatr2() + * - getDiagMatr1() + * - getCompMatr2() + * - createCompMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ static inline CompMatr1 getCompMatr1(qcomp** in) { _validateNewNestedElemsPtrNotNull(in, 1, __func__); @@ -322,8 +332,17 @@ static inline CompMatr1 getCompMatr1(qcomp** in) { } -/// @ingroup matrices_getters -/// @notdoced +/** @ingroup matrices_getters + * @notyetdoced + * + * @see + * - reportCompMatr2() + * - getInlineCompMatr2() + * - getDiagMatr2() + * - createCompMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ static inline CompMatr2 getCompMatr2(qcomp** in) { _validateNewNestedElemsPtrNotNull(in, 2, __func__); @@ -340,8 +359,18 @@ static inline CompMatr2 getCompMatr2(qcomp** in) { } -/// @ingroup matrices_getters -/// @notdoced +/** @ingroup matrices_getters + * @notyetdoced + * + * @see + * - reportDiagMatr1() + * - getInlineDiagMatr1() + * - getCompMatr1() + * - getDiagMatr2() + * - createDiagMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ static inline DiagMatr1 getDiagMatr1(qcomp* in) { _validateNewElemsPtrNotNull(in, __func__); @@ -354,8 +383,17 @@ static inline DiagMatr1 getDiagMatr1(qcomp* in) { } -/// @ingroup matrices_getters -/// @notdoced +/** @ingroup matrices_getters + * @notyetdoced + * + * @see + * - reportDiagMatr2() + * - getInlineDiagMatr2() + * - getCompMatr2() + * - createDiagMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ static inline DiagMatr2 getDiagMatr2(qcomp* in) { _validateNewElemsPtrNotNull(in, __func__); @@ -414,36 +452,70 @@ static inline CompMatr2 _getCompMatr2FromArr(qcomp in[4][4]) { /// @ingroup matrices_getters - /// @notdoced + /// @notyetdoced static inline CompMatr1 getCompMatr1(qcomp in[2][2]) { return _getCompMatr1FromArr(in); } /// @ingroup matrices_getters - /// @notdoced + /// @notyetdoced static inline CompMatr2 getCompMatr2(qcomp in[4][4]) { return _getCompMatr2FromArr(in); } - /// @ingroup matrices_getters - /// @notdoced - /// @cpponly + /** @ingroup matrices_getters + * @notyetdoced + * @cpponly + * + * @see + * - reportCompMatr1() + * - getInlineCompMatr1() + * - getDiagMatr1() + * - getCompMatr2() + * - createCompMatr() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ CompMatr1 getCompMatr1(std::vector> in); - /// @ingroup matrices_getters - /// @notdoced - /// @cpponly + /** @ingroup matrices_getters + * @notyetdoced + * @cpponly + * + * @see + * - reportCompMatr2() + * - getInlineCompMatr2() + * - getDiagMatr2() + * - createCompMatr() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ CompMatr2 getCompMatr2(std::vector> in); - /// @ingroup matrices_getters - /// @notdoced - /// @cpponly + /** @ingroup matrices_getters + * @notyetdoced + * @cpponly + * + * @see + * - reportDiagMatr1() + * - getInlineDiagMatr1() + * - getCompMatr1() + * - getDiagMatr2() + * - createDiagMatr() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ DiagMatr1 getDiagMatr1(std::vector in); - /// @ingroup matrices_getters - /// @notdoced - /// @cpponly + /** @ingroup matrices_getters + * @notyetdoced + * @cpponly + * + * @see + * - reportDiagMatr2() + * - getInlineDiagMatr2() + * - getCompMatr2() + * - createDiagMatr() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ DiagMatr2 getDiagMatr2(std::vector in); @@ -560,24 +632,58 @@ static inline CompMatr2 _getCompMatr2FromArr(qcomp in[4][4]) { // spoofing above macros as functions to doc #if 0 - /// @ingroup matrices_getters - /// @notdoced - /// @macrodoc + /** @ingroup matrices_getters + * @notyetdoced + * @macrodoc + * + * @see + * - reportCompMatr1() + * - getInlineDiagMatr1() + * - getInlineCompMatr2() + * - createCompMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ CompMatr1 getInlineCompMatr1({{ matrix }}); - /// @ingroup matrices_getters - /// @notdoced - /// @macrodoc + /** @ingroup matrices_getters + * @notyetdoced + * @macrodoc + * + * @see + * - reportCompMatr2() + * - getInlineDiagMatr2() + * - createCompMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ CompMatr2 getInlineCompMatr2({{ matrix }}); - /// @ingroup matrices_getters - /// @notdoced - /// @macrodoc + /** @ingroup matrices_getters + * @notyetdoced + * @macrodoc + * + * @see + * - reportDiagMatr1() + * - getInlineCompMatr1() + * - getInlineDiagMatr2() + * - createDiagMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ DiagMatr1 getInlineDiagMatr1({ list }); - /// @ingroup matrices_getters - /// @notdoced - /// @macrodoc + /** @ingroup matrices_getters + * @notyetdoced + * @macrodoc + * + * @see + * - reportDiagMatr2() + * - getInlineCompMatr2() + * - createDiagMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ DiagMatr2 getInlineDiagMatr2({ list }); #endif @@ -595,53 +701,93 @@ extern "C" { #endif - /// @ingroup matrices_create - /// @notdoced + /** @ingroup matrices_create + * @notyetdoced + * + * @see + * - setCompMatr() + * - syncCompMatr() + * - createInlineCompMatr() + * - createDiagMatr() + * - getCompMatr1() + * - getCompMatr2() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ CompMatr createCompMatr(int numQubits); - /// @ingroup matrices_create - /// @notdoced + /** @ingroup matrices_create + * @notyetdoced + * + * @see + * - setDiagMatr() + * - syncDiagMatr() + * - createInlineDiagMatr() + * - createCompMatr() + * - getDiagMatr1() + * - getDiagMatr2() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ DiagMatr createDiagMatr(int numQubits); - /// @ingroup matrices_create - /// @notdoced + /** @ingroup matrices_create + * @notyetdoced + * + * @see + * - createCustomFullStateDiagMatr() + * - setFullStateDiagMatr() + * - syncFullStateDiagMatr() + * - createDiagMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ FullStateDiagMatr createFullStateDiagMatr(int numQubits); - /// @ingroup matrices_create - /// @notdoced + /** @ingroup matrices_create + * @notyetdoced + * + * @see + * - createFullStateDiagMatr() + * - setFullStateDiagMatr() + * - syncFullStateDiagMatr() + * - createDiagMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ FullStateDiagMatr createCustomFullStateDiagMatr(int numQubits, int useDistrib, int useGpuAccel, int useMultithread); /// @ingroup matrices_destroy - /// @notdoced + /// @notyetdoced void destroyCompMatr(CompMatr matrix); /// @ingroup matrices_destroy - /// @notdoced + /// @notyetdoced void destroyDiagMatr(DiagMatr matrix); /// @ingroup matrices_destroy - /// @notdoced + /// @notyetdoced void destroyFullStateDiagMatr(FullStateDiagMatr matrix); /// @ingroup matrices_sync - /// @notdoced + /// @notyetdoced void syncCompMatr(CompMatr matr); /// @ingroup matrices_sync - /// @notdoced + /// @notyetdoced void syncDiagMatr(DiagMatr matr); /// @ingroup matrices_sync - /// @notdoced + /// @notyetdoced void syncFullStateDiagMatr(FullStateDiagMatr matr); @@ -669,19 +815,40 @@ extern "C" { #endif - /// @ingroup matrices_setters - /// @notdoced + /** @ingroup matrices_setters + * @notyetdoced + * + * @see + * - setInlineCompMatr() + * - reportCompMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ void setCompMatr(CompMatr matr, qcomp** vals); - /// @ingroup matrices_setters - /// @notdoced + /** @ingroup matrices_setters + * @notyetdoced + * + * @see + * - setInlineDiagMatr() + * - reportDiagMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ void setDiagMatr(DiagMatr out, qcomp* in); - /// @ingroup matrices_setters - /// @notdoced - /// @nottested + /** @ingroup matrices_setters + * @notyetdoced + * @notyettested + * + * @see + * - setInlineFullStateDiagMatr() + * - reportFullStateDiagMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ void setFullStateDiagMatr(FullStateDiagMatr out, qindex startInd, qcomp* in, qindex numElems); @@ -711,22 +878,40 @@ extern "C" { // C++ defines vector overloads, permitting inline initialisation - /// @ingroup matrices_setters - /// @notdoced - /// @cpponly + /** @ingroup matrices_setters + * @notyetdoced + * @cpponly + * + * @see + * - setInlineCompMatr() + * - reportCompMatr() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ void setCompMatr(CompMatr out, std::vector> in); - /// @ingroup matrices_setters - /// @notdoced - /// @cpponly + /** @ingroup matrices_setters + * @notyetdoced + * @cpponly + * + * @see + * - setInlineDiagMatr() + * - reportDiagMatr() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ void setDiagMatr(DiagMatr out, std::vector in); - /// @ingroup matrices_setters - /// @notdoced - /// @nottested - /// @cpponly + /** @ingroup matrices_setters + * @notyetdoced + * @notyettested + * @cpponly + * + * @see + * - setInlineFullStateDiagMatr() + * - reportFullStateDiagMatr() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ void setFullStateDiagMatr(FullStateDiagMatr out, qindex startInd, std::vector in); @@ -776,10 +961,16 @@ extern "C" { // spoofing above macro as functions to doc #if 0 - /// @ingroup matrices_setters - /// @notdoced - /// @macrodoc - /// @conly + /** @ingroup matrices_setters + * @notyetdoced + * @macrodoc + * @conly + * + * @see + * - setInlineCompMatr() + * - reportCompMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) examples + */ void setCompMatr(CompMatr matr, qcomp arr[matr.numRows][matr.numRows]); #endif @@ -816,22 +1007,39 @@ extern "C" { // validate that they match the struct dimensions (which requires validating the structs). - /// @ingroup matrices_setters - /// @notdoced - /// @cpponly + /** @ingroup matrices_setters + * @notyetdoced + * @cpponly + * + * @see + * - reportCompMatr() + * - createInlineCompMatr() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ void setInlineCompMatr(CompMatr matr, int numQb, std::vector> in); - /// @ingroup matrices_setters - /// @notdoced - /// @cpponly + /** @ingroup matrices_setters + * @notyetdoced + * @cpponly + * + * @see + * - reportDiagMatr() + * - createInlineDiagMatr() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ void setInlineDiagMatr(DiagMatr matr, int numQb, std::vector in); - /// @ingroup matrices_setters - /// @notdoced - /// @nottested - /// @cpponly + /** @ingroup matrices_setters + * @notyetdoced + * @notyettested + * @cpponly + * + * @see + * - reportFullStateDiagMatr() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ void setInlineFullStateDiagMatr(FullStateDiagMatr matr, qindex startInd, qindex numElems, std::vector in); @@ -893,22 +1101,43 @@ extern "C" { // spoofing above macros as functions to doc #if 0 - /// @ingroup matrices_setters - /// @notdoced - /// @macrodoc + + /** @ingroup matrices_setters + * @notyetdoced + * @macrodoc + * + * @see + * - reportCompMatr() + * - createInlineCompMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) examples + */ void setInlineCompMatr(CompMatr matr, int numQb, {{ matrix }}); - /// @ingroup matrices_setters - /// @notdoced - /// @macrodoc + + /** @ingroup matrices_setters + * @notyetdoced + * @macrodoc + * + * @see + * - reportDiagMatr() + * - createInlineDiagMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) examples + */ void setInlineDiagMatr(DiagMatr matr, int numQb, { list }); - /// @ingroup matrices_setters - /// @nottested - /// @notdoced - /// @macrodoc + + /** @ingroup matrices_setters + * @notyettested + * @notyetdoced + * @macrodoc + * + * @see + * - reportFullStateDiagMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) examples + */ void setInlineFullStateDiagMatr(FullStateDiagMatr matr, qindex startInd, qindex numElems, { list }); + #endif @@ -975,15 +1204,25 @@ extern "C" { // C++ accepts vector initialiser lists - /// @ingroup matrices_create - /// @notdoced - /// @cpponly + /** @ingroup matrices_create + * @notyetdoced + * @cpponly + * + * @see + * - reportCompMatr() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ CompMatr createInlineCompMatr(int numQb, std::vector> elems); - /// @ingroup matrices_create - /// @notdoced - /// @cpponly + /** @ingroup matrices_create + * @notyetdoced + * @cpponly + * + * @see + * - reportDiagMatr() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.cpp) examples + */ DiagMatr createInlineDiagMatr(int numQb, std::vector elems); @@ -1031,16 +1270,29 @@ extern "C" { // spoofing above macros as functions to doc #if 0 - /// @ingroup matrices_create - /// @notdoced - /// @macrodoc + + /** @ingroup matrices_create + * @notyetdoced + * @macrodoc + * + * @see + * - reportCompMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) examples + */ CompMatr createInlineCompMatr(int numQb, {{ matrix }}); - /// @ingroup matrices_create - /// @notdoced - /// @macrodoc + + /** @ingroup matrices_create + * @notyetdoced + * @macrodoc + * + * @see + * - reportDiagMatr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_matrices.c) examples + */ DiagMatr createInlineDiagMatr(int numQb, { list }); + #endif #else @@ -1069,38 +1321,38 @@ extern "C" { /// @ingroup matrices_setters - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested void setDiagMatrFromMultiVarFunc(DiagMatr out, qcomp (*func)(qindex*), int* numQubitsPerVar, int numVars, int areSigned); /// @ingroup matrices_setters - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested void setDiagMatrFromMultiDimLists(DiagMatr out, void* lists, int* numQubitsPerDim, int numDims); /// @ingroup matrices_create - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested FullStateDiagMatr createFullStateDiagMatrFromPauliStrSum(PauliStrSum in); /// @ingroup matrices_setters - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested void setFullStateDiagMatrFromPauliStrSum(FullStateDiagMatr out, PauliStrSum in); /// @ingroup matrices_setters - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested void setFullStateDiagMatrFromMultiVarFunc(FullStateDiagMatr out, qcomp (*func)(qindex*), int* numQubitsPerVar, int numVars, int areSigned); /// @ingroup matrices_setters - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested void setFullStateDiagMatrFromMultiDimLists(FullStateDiagMatr out, void* lists, int* numQubitsPerDim, int numDims); @@ -1121,45 +1373,75 @@ extern "C" { #endif - /// @ingroup matrices_reporters - /// @notdoced - /// @nottested + /** @ingroup matrices_reporters + * @notyetdoced + * @notyettested + * + * @see + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.cpp) examples + */ void reportCompMatr1(CompMatr1 matrix); - /// @ingroup matrices_reporters - /// @notdoced - /// @nottested + /** @ingroup matrices_reporters + * @notyetdoced + * @notyettested + * + * @see + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.cpp) examples + */ void reportCompMatr2(CompMatr2 matrix); - /// @ingroup matrices_reporters - /// @notdoced - /// @nottested + /** @ingroup matrices_reporters + * @notyetdoced + * @notyettested + * + * @see + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.cpp) examples + */ void reportCompMatr(CompMatr matrix); - /// @ingroup matrices_reporters - /// @notdoced - /// @nottested + /** @ingroup matrices_reporters + * @notyetdoced + * @notyettested + * + * @see + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.cpp) examples + */ void reportDiagMatr1(DiagMatr1 matrix); - /// @ingroup matrices_reporters - /// @notdoced - /// @nottested + /** @ingroup matrices_reporters + * @notyetdoced + * @notyettested + * + * @see + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.cpp) examples + */ void reportDiagMatr2(DiagMatr2 matrix); /// @ingroup matrices_reporters - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested void reportDiagMatr(DiagMatr matrix); - /// @ingroup matrices_reporters - /// @notdoced - /// @nottested + /** @ingroup matrices_reporters + * @notyetdoced + * @notyettested + * + * @see + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_matrices.cpp) examples + */ void reportFullStateDiagMatr(FullStateDiagMatr matr); diff --git a/quest/include/modes.h b/quest/include/modes.h index 84e030488..b90797acd 100644 --- a/quest/include/modes.h +++ b/quest/include/modes.h @@ -93,17 +93,17 @@ #if 0 - /// @notdoced + /// @notyetdoced /// @macrodoc const int PERMIT_NODES_TO_SHARE_GPU = 0; - /// @notdoced + /// @notyetdoced /// @macrodoc const int INCLUDE_DEPRECATED_FUNCTIONS = 0; - /// @notdoced + /// @notyetdoced /// @macrodoc const int DISABLE_DEPRECATION_WARNINGS = 0; diff --git a/quest/include/operations.h b/quest/include/operations.h index d4e208a12..57e1dab31 100644 --- a/quest/include/operations.h +++ b/quest/include/operations.h @@ -81,7 +81,7 @@ extern "C" { * @param[in,out] qureg the state to modify. * @param[in] target the index of the target qubit. * @param[in] matrix the Z-basis matrix to multiply. - * @throws invalidQuESTInputError() + * @throws @validationerror * - if @p qureg or @p matrix are uninitialised. * - if @p target is an invalid qubit index. * @see @@ -153,7 +153,7 @@ digraph { * @param[in,out] qureg the state to modify. * @param[in] target the index of the target qubit. * @param[in] matrix the Z-basis unitary matrix to effect. - * @throws invalidQuESTInputError() + * @throws @validationerror * - if @p qureg or @p matrix are uninitialised. * - if @p matrix is not approximately unitary. * - if @p target is an invalid qubit index. @@ -169,7 +169,9 @@ digraph { void applyCompMatr1(Qureg qureg, int target, CompMatr1 matrix); -/** Applies a singly-controlled one-qubit dense unitary @p matrix to the specified +/** @notyetdoced + * + * Applies a singly-controlled one-qubit dense unitary @p matrix to the specified * @p target qubit of @p qureg. * * @diagram @@ -198,12 +200,15 @@ digraph { } * @enddot * - * @notdoced + * @see + * - applyCompMatr1() */ void applyControlledCompMatr1(Qureg qureg, int control, int target, CompMatr1 matrix); -/** Applies a multiply-controlled one-qubit dense unitary @p matrix to the specified +/** @notyetdoced + * + * Applies a multiply-controlled one-qubit dense unitary @p matrix to the specified * @p target qubit of @p qureg. * * @diagram @@ -240,12 +245,15 @@ digraph { } * @enddot * - * @notdoced + * @see + * - applyCompMatr1() */ void applyMultiControlledCompMatr1(Qureg qureg, int* controls, int numControls, int target, CompMatr1 matrix); -/** Applies an arbitrarily-controlled one-qubit dense unitary @p matrix to the specified +/** @notyetdoced + * + * Applies an arbitrarily-controlled one-qubit dense unitary @p matrix to the specified * @p target qubit of @p qureg, conditioned upon the @p controls being in the given @p states. * * @diagram @@ -282,7 +290,8 @@ digraph { } * @enddot * - * @notdoced + * @see + * - applyCompMatr1() */ void applyMultiStateControlledCompMatr1(Qureg qureg, int* controls, int* states, int numControls, int target, CompMatr1 matrix); @@ -295,17 +304,19 @@ void applyMultiStateControlledCompMatr1(Qureg qureg, int* controls, int* states, #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledCompMatr1() void applyMultiControlledCompMatr1(Qureg qureg, std::vector controls, int target, CompMatr1 matrix); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledCompMatr1() void applyMultiStateControlledCompMatr1(Qureg qureg, std::vector controls, std::vector states, int target, CompMatr1 matrix); @@ -327,11 +338,16 @@ extern "C" { #endif -/// @notdoced +/// @notyetdoced +/// @see +/// - applyCompMatr2() +/// - multiplyCompMatr1() void multiplyCompMatr2(Qureg qureg, int target1, int target2, CompMatr2 matr); -/** Applies a general two-qubit dense unitary @p matrix to qubits @p target1 and +/** @notyetdoced + * + * Applies a general two-qubit dense unitary @p matrix to qubits @p target1 and * @p target2 (treated as increasing significance) of @p qureg. * * @diagram @@ -355,12 +371,15 @@ digraph { } * @enddot * - * @notdoced + * @see + * - applyCompMatr1() */ void applyCompMatr2(Qureg qureg, int target1, int target2, CompMatr2 matrix); -/** Applies a singly-controlled two-qubit dense unitary @p matrix to qubits +/** @notyetdoced + * + * Applies a singly-controlled two-qubit dense unitary @p matrix to qubits * @p target1 and @p target2 (treated as increasing significance) of @p qureg. * * @diagram @@ -390,12 +409,15 @@ digraph { } * @enddot * - * @notdoced + * @see + * - applyCompMatr2() */ void applyControlledCompMatr2(Qureg qureg, int control, int target1, int target2, CompMatr2 matr); -/** Applies a multiply-controlled two-qubit dense unitary @p matrix to qubits +/** @notyetdoced + * + * Applies a multiply-controlled two-qubit dense unitary @p matrix to qubits * @p target1 and @p target2 (treated as increasing significance) of @p qureg. * * @diagram @@ -431,12 +453,15 @@ digraph { } * @enddot * - * @notdoced + * @see + * - applyCompMatr2() */ void applyMultiControlledCompMatr2(Qureg qureg, int* controls, int numControls, int target1, int target2, CompMatr2 matr); -/** Applies an arbitrarily-controlled two-qubit dense unitary @p matrix to qubits +/** @notyetdoced + * + * Applies an arbitrarily-controlled two-qubit dense unitary @p matrix to qubits * @p target1 and @p target2 (treated as increasing significance) of @p qureg, * conditioned upon the @p controls being in the given @p states. * @@ -473,7 +498,9 @@ digraph { } * @enddot * - * @notdoced + * @see + * - applyCompMatr2() + * - applyMultiStateControlledCompMatr1() */ void applyMultiStateControlledCompMatr2(Qureg qureg, int* controls, int* states, int numControls, int target1, int target2, CompMatr2 matr); @@ -486,17 +513,19 @@ void applyMultiStateControlledCompMatr2(Qureg qureg, int* controls, int* states, #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledCompMatr2() void applyMultiControlledCompMatr2(Qureg qureg, std::vector controls, int target1, int target2, CompMatr2 matr); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledCompMatr2() void applyMultiStateControlledCompMatr2(Qureg qureg, std::vector controls, std::vector states, int numControls, int target1, int target2, CompMatr2 matr); @@ -518,23 +547,51 @@ extern "C" { #endif -/// @notdoced -void multiplyCompMatr(Qureg qureg, int* targets, int numTargets, CompMatr matr); +/** @notyetdoced + * + * @see + * - applyCompMatr() + * - multiplyCompMatr1() + */ +void multiplyCompMatr(Qureg qureg, int* targets, int numTargets, CompMatr matrix); -/// @notdoced +/** @notyetdoced + * + * @formulae + * + * Let @f$ M = @f$ @p matrix. + * The qubits within @p targets are treated to be ordered least to most significant with respect + * to @f$ M @f$. That is, if @f$ M @f$ was hypothetically separable single-qubit matrices + * @f[ + M \equiv A \otimes B \otimes C \otimes \dots + * @f] + * then this function would effect + * @f[ + \hat{M}_{\text{targets}} \equiv A_{\text{targets}[0]} B_{\text{targets}[1]} C_{\text{targets}[2]} \dots + * @f] + * + * @see + * - applyCompMatr1() + */ void applyCompMatr(Qureg qureg, int* targets, int numTargets, CompMatr matr); -/// @notdoced +/// @notyetdoced +/// @see +/// - applyControlledCompMatr1() void applyControlledCompMatr(Qureg qureg, int control, int* targets, int numTargets, CompMatr matr); -/// @notdoced +/// @notyetdoced +/// @see +/// - applyMultiControlledCompMatr1() void applyMultiControlledCompMatr(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, CompMatr matr); -/// @notdoced +/// @notyetdoced +/// @see +/// - applyMultiStateControlledCompMatr1() void applyMultiStateControlledCompMatr(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, CompMatr matr); @@ -546,38 +603,43 @@ void applyMultiStateControlledCompMatr(Qureg qureg, int* controls, int* states, #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see multiplyCompMatr() void multiplyCompMatr(Qureg qureg, std::vector targets, CompMatr matr); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyCompMatr() void applyCompMatr(Qureg qureg, std::vector targets, CompMatr matr); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyControlledCompMatr() void applyControlledCompMatr(Qureg qureg, int control, std::vector targets, CompMatr matr); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledCompMatr() void applyMultiControlledCompMatr(Qureg qureg, std::vector controls, std::vector targets, CompMatr matr); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledCompMatr() void applyMultiStateControlledCompMatr(Qureg qureg, std::vector controls, std::vector states, std::vector targets, CompMatr matr); @@ -599,23 +661,28 @@ extern "C" { #endif -/// @notdoced +/// @notyetdoced +/// @see multiplyCompMatr1() void multiplyDiagMatr1(Qureg qureg, int target, DiagMatr1 matr); -/// @notdoced +/// @notyetdoced +/// @see applyCompMatr1() void applyDiagMatr1(Qureg qureg, int target, DiagMatr1 matr); -/// @notdoced +/// @notyetdoced +/// @see applyControlledCompMatr1() void applyControlledDiagMatr1(Qureg qureg, int control, int target, DiagMatr1 matr); -/// @notdoced +/// @notyetdoced +/// @see applyMultiControlledCompMatr1() void applyMultiControlledDiagMatr1(Qureg qureg, int* controls, int numControls, int target, DiagMatr1 matr); -/// @notdoced +/// @notyetdoced +/// @see applyMultiStateControlledCompMatr1() void applyMultiStateControlledDiagMatr1(Qureg qureg, int* controls, int* states, int numControls, int target, DiagMatr1 matr); @@ -627,17 +694,19 @@ void applyMultiStateControlledDiagMatr1(Qureg qureg, int* controls, int* states, #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledDiagMatr1() void applyMultiControlledDiagMatr1(Qureg qureg, std::vector controls, int target, DiagMatr1 matr); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledDiagMatr1() void applyMultiStateControlledDiagMatr1(Qureg qureg, std::vector controls, std::vector states, int target, DiagMatr1 matr); @@ -659,23 +728,28 @@ extern "C" { #endif -/// @notdoced +/// @notyetdoced +/// @see multiplyCompMatr1() void multiplyDiagMatr2(Qureg qureg, int target1, int target2, DiagMatr2 matr); -/// @notdoced +/// @notyetdoced +/// @see applyCompMatr1() void applyDiagMatr2(Qureg qureg, int target1, int target2, DiagMatr2 matr); -/// @notdoced +/// @notyetdoced +/// @see applyControlledCompMatr1() void applyControlledDiagMatr2(Qureg qureg, int control, int target1, int target2, DiagMatr2 matr); -/// @notdoced +/// @notyetdoced +/// @see applyMultiControlledCompMatr1() void applyMultiControlledDiagMatr2(Qureg qureg, int* controls, int numControls, int target1, int target2, DiagMatr2 matr); -/// @notdoced +/// @notyetdoced +/// @see applyMultiStateControlledCompMatr1() void applyMultiStateControlledDiagMatr2(Qureg qureg, int* controls, int* states, int numControls, int target1, int target2, DiagMatr2 matr); @@ -687,17 +761,19 @@ void applyMultiStateControlledDiagMatr2(Qureg qureg, int* controls, int* states, #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledDiagMatr2() void applyMultiControlledDiagMatr2(Qureg qureg, std::vector controls, int target1, int target2, DiagMatr2 matr); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledDiagMatr2() void applyMultiStateControlledDiagMatr2(Qureg qureg, std::vector controls, std::vector states, int target1, int target2, DiagMatr2 matr); @@ -719,43 +795,65 @@ extern "C" { #endif -/// @notdoced +/// @notyetdoced +/// @see multiplyCompMatr1() void multiplyDiagMatr(Qureg qureg, int* targets, int numTargets, DiagMatr matrix); -/// @notdoced +/// @notyetdoced +/// @see applyCompMatr1() void applyDiagMatr(Qureg qureg, int* targets, int numTargets, DiagMatr matrix); -/// @notdoced +/// @notyetdoced +/// @see applyControlledCompMatr1() void applyControlledDiagMatr(Qureg qureg, int control, int* targets, int numTargets, DiagMatr matrix); -/// @notdoced +/// @notyetdoced +/// @see applyMultiControlledCompMatr1() void applyMultiControlledDiagMatr(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, DiagMatr matrix); -/// @notdoced +/// @notyetdoced +/// @see applyMultiStateControlledCompMatr1() void applyMultiStateControlledDiagMatr(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, DiagMatr matrix); -/// @notdoced +/// @notyetdoced +/// @see +/// - multiplyCompMatr1() +/// - applyDiagMatrPower() void multiplyDiagMatrPower(Qureg qureg, int* targets, int numTargets, DiagMatr matrix, qcomp exponent); -/// @notdoced +/** @notyetdoced + * + * @formulae + * + * This function is equivalent to applyDiagMatr() except that @p matrix is raised to the given @p exponent. + */ void applyDiagMatrPower(Qureg qureg, int* targets, int numTargets, DiagMatr matrix, qcomp exponent); -/// @notdoced +/// @notyetdoced +/// @see +/// - applyDiagMatrPower() +/// - applyControlledCompMatr1() void applyControlledDiagMatrPower(Qureg qureg, int control, int* targets, int numTargets, DiagMatr matrix, qcomp exponent); -/// @notdoced +/// @notyetdoced +/// @see +/// - applyDiagMatrPower() +/// - applyMultiControlledCompMatr1() void applyMultiControlledDiagMatrPower(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, DiagMatr matrix, qcomp exponent); -/// @notdoced +/// @notyetdoced +/// @see +/// - applyDiagMatrPower() +/// - applyMultiStateControlledCompMatr1() void applyMultiStateControlledDiagMatrPower(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, DiagMatr matrix, qcomp exponent); @@ -767,73 +865,83 @@ void applyMultiStateControlledDiagMatrPower(Qureg qureg, int* controls, int* sta #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see multiplyDiagMatr() void multiplyDiagMatr(Qureg qureg, std::vector targets, DiagMatr matrix); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyDiagMatr() void applyDiagMatr(Qureg qureg, std::vector targets, DiagMatr matrix); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyControlledDiagMatr() void applyControlledDiagMatr(Qureg qureg, int control, std::vector targets, DiagMatr matrix); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledDiagMatr() void applyMultiControlledDiagMatr(Qureg qureg, std::vector controls, std::vector targets, DiagMatr matrix); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledDiagMatr() void applyMultiStateControlledDiagMatr(Qureg qureg, std::vector controls, std::vector states, std::vector targets, DiagMatr matrix); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see multiplyDiagMatrPower() void multiplyDiagMatrPower(Qureg qureg, std::vector targets, DiagMatr matrix, qcomp exponent); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyDiagMatrPower() void applyDiagMatrPower(Qureg qureg, std::vector targets, DiagMatr matrix, qcomp exponent); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyControlledDiagMatrPower() void applyControlledDiagMatrPower(Qureg qureg, int control, std::vector targets, DiagMatr matrix, qcomp exponent); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledDiagMatrPower() void applyMultiControlledDiagMatrPower(Qureg qureg, std::vector controls, std::vector targets, DiagMatr matrix, qcomp exponent); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledDiagMatrPower() void applyMultiStateControlledDiagMatrPower(Qureg qureg, std::vector controls, std::vector states, std::vector targets, DiagMatr matrix, qcomp exponent); @@ -855,23 +963,30 @@ extern "C" { #endif -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated +/// @see +/// - multiplyCompMatr1 void multiplyFullStateDiagMatr(Qureg qureg, FullStateDiagMatr matrix); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated +/// @see +/// - multiplyCompMatr1 +/// - applyDiagMatrPower void multiplyFullStateDiagMatrPower(Qureg qureg, FullStateDiagMatr matrix, qcomp exponent); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void applyFullStateDiagMatr(Qureg qureg, FullStateDiagMatr matrix); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated +/// @see +/// - applyDiagMatrPower void applyFullStateDiagMatrPower(Qureg qureg, FullStateDiagMatr matrix, qcomp exponent); @@ -897,51 +1012,54 @@ extern "C" { #endif -/// @notdoced +/// @notyetdoced void applyS(Qureg qureg, int target); -/// @notdoced +/// @notyetdoced void applyControlledS(Qureg qureg, int control, int target); -/// @notdoced +/// @notyetdoced void applyMultiControlledS(Qureg qureg, int* controls, int numControls, int target); -/// @notdoced +/// @notyetdoced +/// @see applyMultiStateControlledCompMatr1() void applyMultiStateControlledS(Qureg qureg, int* controls, int* states, int numControls, int target); -/// @notdoced +/// @notyetdoced void applyT(Qureg qureg, int target); -/// @notdoced +/// @notyetdoced void applyControlledT(Qureg qureg, int control, int target); -/// @notdoced +/// @notyetdoced void applyMultiControlledT(Qureg qureg, int* controls, int numControls, int target); -/// @notdoced +/// @notyetdoced +/// @see applyMultiStateControlledCompMatr1() void applyMultiStateControlledT(Qureg qureg, int* controls, int* states, int numControls, int target); -/// @notdoced +/// @notyetdoced void applyHadamard(Qureg qureg, int target); -/// @notdoced +/// @notyetdoced void applyControlledHadamard(Qureg qureg, int control, int target); -/// @notdoced +/// @notyetdoced void applyMultiControlledHadamard(Qureg qureg, int* controls, int numControls, int target); -/// @notdoced +/// @notyetdoced +/// @see applyMultiStateControlledCompMatr1() void applyMultiStateControlledHadamard(Qureg qureg, int* controls, int* states, int numControls, int target); @@ -953,45 +1071,51 @@ void applyMultiStateControlledHadamard(Qureg qureg, int* controls, int* states, #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledS() void applyMultiControlledS(Qureg qureg, std::vector controls, int target); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledS() void applyMultiStateControlledS(Qureg qureg, std::vector controls, std::vector states, int target); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledT() void applyMultiControlledT(Qureg qureg, std::vector controls, int target); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledT() void applyMultiStateControlledT(Qureg qureg, std::vector controls, std::vector states, int target); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledHadamard() void applyMultiControlledHadamard(Qureg qureg, std::vector controls, int target); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledHadamard() void applyMultiStateControlledHadamard(Qureg qureg, std::vector controls, std::vector states, int target); @@ -1013,7 +1137,8 @@ extern "C" { #endif -/// @notdoced +/// @notyetdoced +/// @see multiplyCompMatr1() void multiplySwap(Qureg qureg, int qubit1, int qubit2); @@ -1044,36 +1169,38 @@ digraph { } * @enddot * - * @notdoced + * @notyetdoced */ void applySwap(Qureg qureg, int qubit1, int qubit2); -/// @notdoced +/// @notyetdoced void applyControlledSwap(Qureg qureg, int control, int qubit1, int qubit2); -/// @notdoced +/// @notyetdoced void applyMultiControlledSwap(Qureg qureg, int* controls, int numControls, int qubit1, int qubit2); -/// @notdoced +/// @notyetdoced +/// @see applyMultiStateControlledCompMatr1() void applyMultiStateControlledSwap(Qureg qureg, int* controls, int* states, int numControls, int qubit1, int qubit2); -/// @notdoced +/// @notyetdoced void applySqrtSwap(Qureg qureg, int qubit1, int qubit2); -/// @notdoced +/// @notyetdoced void applyControlledSqrtSwap(Qureg qureg, int control, int qubit1, int qubit2); -/// @notdoced +/// @notyetdoced void applyMultiControlledSqrtSwap(Qureg qureg, int* controls, int numControls, int qubit1, int qubit2); -/// @notdoced +/// @notyetdoced +/// @see applyMultiStateControlledCompMatr1() void applyMultiStateControlledSqrtSwap(Qureg qureg, int* controls, int* states, int numControls, int qubit1, int qubit2); @@ -1085,31 +1212,35 @@ void applyMultiStateControlledSqrtSwap(Qureg qureg, int* controls, int* states, #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledSwap() void applyMultiControlledSwap(Qureg qureg, std::vector controls, int qubit1, int qubit2); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledSwap() void applyMultiStateControlledSwap(Qureg qureg, std::vector controls, std::vector states, int qubit1, int qubit2); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledSqrtSwap() void applyMultiControlledSqrtSwap(Qureg qureg, std::vector controls, int qubit1, int qubit2); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledSqrtSwap() void applyMultiStateControlledSqrtSwap(Qureg qureg, std::vector controls, std::vector states, int numControls, int qubit1, int qubit2); @@ -1131,63 +1262,69 @@ extern "C" { #endif -/// @notdoced +/// @notyetdoced +/// @see multiplyCompMatr1() void multiplyPauliX(Qureg qureg, int target); -/// @notdoced +/// @notyetdoced +/// @see multiplyCompMatr1() void multiplyPauliY(Qureg qureg, int target); -/// @notdoced +/// @notyetdoced +/// @see multiplyCompMatr1() void multiplyPauliZ(Qureg qureg, int target); -/// @notdoced +/// @notyetdoced void applyPauliX(Qureg qureg, int target); -/// @notdoced +/// @notyetdoced void applyPauliY(Qureg qureg, int target); -/// @notdoced +/// @notyetdoced void applyPauliZ(Qureg qureg, int target); -/// @notdoced +/// @notyetdoced void applyControlledPauliX(Qureg qureg, int control, int target); -/// @notdoced +/// @notyetdoced void applyControlledPauliY(Qureg qureg, int control, int target); -/// @notdoced +/// @notyetdoced void applyControlledPauliZ(Qureg qureg, int control, int target); -/// @notdoced +/// @notyetdoced void applyMultiControlledPauliX(Qureg qureg, int* controls, int numControls, int target); -/// @notdoced +/// @notyetdoced void applyMultiControlledPauliY(Qureg qureg, int* controls, int numControls, int target); -/// @notdoced +/// @notyetdoced void applyMultiControlledPauliZ(Qureg qureg, int* controls, int numControls, int target); -/// @notdoced +/// @notyetdoced +/// @see applyMultiStateControlledCompMatr1() void applyMultiStateControlledPauliX(Qureg qureg, int* controls, int* states, int numControls, int target); -/// @notdoced +/// @notyetdoced +/// @see applyMultiStateControlledCompMatr1() void applyMultiStateControlledPauliY(Qureg qureg, int* controls, int* states, int numControls, int target); -/// @notdoced +/// @notyetdoced +/// @see applyMultiStateControlledCompMatr1() void applyMultiStateControlledPauliZ(Qureg qureg, int* controls, int* states, int numControls, int target); @@ -1199,45 +1336,51 @@ void applyMultiStateControlledPauliZ(Qureg qureg, int* controls, int* states, in #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledPauliX() void applyMultiControlledPauliX(Qureg qureg, std::vector controls, int target); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledPauliY() void applyMultiControlledPauliY(Qureg qureg, std::vector controls, int target); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledPauliZ() void applyMultiControlledPauliZ(Qureg qureg, std::vector controls, int target); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledPauliX() void applyMultiStateControlledPauliX(Qureg qureg, std::vector controls, std::vector states, int target); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledPauliY() void applyMultiStateControlledPauliY(Qureg qureg, std::vector controls, std::vector states, int target); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledPauliZ() void applyMultiStateControlledPauliZ(Qureg qureg, std::vector controls, std::vector states, int target); @@ -1259,23 +1402,25 @@ extern "C" { #endif -/// @notdoced +/// @notyetdoced +/// @see multiplyCompMatr1() void multiplyPauliStr(Qureg qureg, PauliStr str); -/// @notdoced +/// @notyetdoced void applyPauliStr(Qureg qureg, PauliStr str); -/// @notdoced +/// @notyetdoced void applyControlledPauliStr(Qureg qureg, int control, PauliStr str); -/// @notdoced +/// @notyetdoced void applyMultiControlledPauliStr(Qureg qureg, int* controls, int numControls, PauliStr str); -/// @notdoced +/// @notyetdoced +/// @see applyMultiStateControlledCompMatr1() void applyMultiStateControlledPauliStr(Qureg qureg, int* controls, int* states, int numControls, PauliStr str); @@ -1287,17 +1432,19 @@ void applyMultiStateControlledPauliStr(Qureg qureg, int* controls, int* states, #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledPauliStr() void applyMultiControlledPauliStr(Qureg qureg, std::vector controls, PauliStr str); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledPauliStr() void applyMultiStateControlledPauliStr(Qureg qureg, std::vector controls, std::vector states, PauliStr str); @@ -1319,67 +1466,235 @@ extern "C" { #endif -/// @notdoced +/** @notyetdoced + * + * @formulae + * + * Let @f$ \theta = @f$ @p angle. + * This function effects unitary + * @f[ + \hat{R}_{x}(\theta) + = + \exp \left( + - \iu \frac{\theta}{2} + \hat{\sigma}_x + \right) + * @f] + * upon the @p target qubit, where @f$ \hat{\sigma}_x @f$ is the Pauli X matrix. + * + * @equivalences + * - This function is entirely equivalent to calling applyPauliGadget() with a single-site PauliStr. + * ``` + applyPauliGadget(qureg, getInlinePauliStr("X", {target}), angle); + * ``` + * - This function is faster than, but otherwise equivalent to, invoking applyRotateAroundAxis() + * with an axis vector equal to the X-axis. + * ``` + applyRotateAroundAxis(qureg, target, qreal angle, 1,0,0); + * ``` + * - This function is faster than, but otherwise equivalent to, effecting @f$ \hat{R}_{x}(\theta) @f$ as a CompMatr1. + * ``` + qcomp c = cos(angle/2); + qcomp s = sin(angle/2) * (-1.i); + CompMatr1 matr = getInlineCompMatr1({{c, s}, {s, c}}); + applyCompMatr1(qureg, target, matr); + * ``` + * - Passing @p angle=0 is equivalent to effecting the identity, leaving the state unchanged. + */ void applyRotateX(Qureg qureg, int target, qreal angle); -/// @notdoced +/** @notyetdoced + * + * @formulae + * + * Let @f$ \theta = @f$ @p angle. + * This function effects unitary + * @f[ + \hat{R}_{y}(\theta) + = + \exp \left( + - \iu \frac{\theta}{2} + \hat{\sigma}_y + \right) + * @f] + * upon the @p target qubit, where @f$ \hat{\sigma}_y @f$ is the Pauli Y matrix. + * + * @equivalences + * - This function is entirely equivalent to calling applyPauliGadget() with a single-site PauliStr. + * ``` + applyPauliGadget(qureg, getInlinePauliStr("Y", {target}), angle); + * ``` + * - This function is faster than, but otherwise equivalent to, invoking applyRotateAroundAxis() + * with an axis vector equal to the Y-axis. + * ``` + applyRotateAroundAxis(qureg, target, qreal angle, 0,1,0); + * ``` + * - This function is faster than, but otherwise equivalent to, effecting @f$ \hat{R}_{y}(\theta) @f$ as a CompMatr1. + * ``` + qcomp c = cos(angle/2); + qcomp s = sin(angle/2); + CompMatr1 matr = getInlineCompMatr1({{c, -s}, {s, c}}); + applyCompMatr1(qureg, target, matr); + * ``` + * - Passing @p angle=0 is equivalent to effecting the identity, leaving the state unchanged. + */ void applyRotateY(Qureg qureg, int target, qreal angle); -/// @notdoced +/** @notyetdoced + * + * @formulae + * + * Let @f$ \theta = @f$ @p angle. + * This function effects unitary + * @f[ + \hat{R}_{z}(\theta) + = + \exp \left( + - \iu \frac{\theta}{2} + \hat{\sigma}_z + \right) + * @f] + * upon the @p target qubit, where @f$ \hat{\sigma}_z @f$ is the Pauli Z matrix. + * + * @equivalences + * - This function is entirely equivalent to calling applyPauliGadget() with a single-site PauliStr. + * ``` + applyPauliGadget(qureg, getInlinePauliStr("Z", {target}), angle); + * ``` + * - This function is faster than, but otherwise equivalent to, invoking applyRotateAroundAxis() + * with an axis vector equal to the Z-axis. + * ``` + applyRotateAroundAxis(qureg, target, qreal angle, 0,0,1); + * ``` + * - This function is faster than, but otherwise equivalent to, effecting @f$ \hat{R}_{z}(\theta) @f$ as a DiagMatr1. + * ``` + qcomp a = cexp(- angle / 2 * 1.i); + qcomp b = cexp( angle / 2 * 1.i); + DiagMatr1 matr = getInlineDiagMatr1({a, b}); + applyDiagMatr1(qureg, target, matr); + * ``` + * - Passing @p angle=0 is equivalent to effecting the identity, leaving the state unchanged. + */ void applyRotateZ(Qureg qureg, int target, qreal angle); -/// @notdoced +/// @notyetdoced void applyControlledRotateX(Qureg qureg, int control, int target, qreal angle); -/// @notdoced +/// @notyetdoced void applyControlledRotateY(Qureg qureg, int control, int target, qreal angle); -/// @notdoced +/// @notyetdoced void applyControlledRotateZ(Qureg qureg, int control, int target, qreal angle); -/// @notdoced +/// @notyetdoced void applyMultiControlledRotateX(Qureg qureg, int* controls, int numControls, int target, qreal angle); -/// @notdoced +/// @notyetdoced void applyMultiControlledRotateY(Qureg qureg, int* controls, int numControls, int target, qreal angle); -/// @notdoced +/// @notyetdoced void applyMultiControlledRotateZ(Qureg qureg, int* controls, int numControls, int target, qreal angle); -/// @notdoced +/// @notyetdoced +/// @see +/// - applyRotateX() +/// - applyMultiStateControlledCompMatr1() void applyMultiStateControlledRotateX(Qureg qureg, int* controls, int* states, int numControls, int target, qreal angle); -/// @notdoced +/// @notyetdoced +/// @see +/// - applyRotateY() +/// - applyMultiStateControlledCompMatr1() void applyMultiStateControlledRotateY(Qureg qureg, int* controls, int* states, int numControls, int target, qreal angle); -/// @notdoced +/// @notyetdoced +/// @see +/// - applyRotateZ() +/// - applyMultiStateControlledCompMatr1() void applyMultiStateControlledRotateZ(Qureg qureg, int* controls, int* states, int numControls, int target, qreal angle); -/// @notdoced -void applyRotateAroundAxis(Qureg qureg, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ); +/** @notyetdoced + * + * @formulae + * + * Let @f$ \theta = @f$ @p angle and @f$ \vec{n} = ( @f$ @p axisX, @p axisY, @p axisZ @f$ ) @f$, + * with corresponding unit vector @f$ \bar{n} @f$. + * Further, let @f$ \vec{\sigma} = (\hat{\sigma}_x, \hat{\sigma}_y, \hat{\sigma}_z) @f$ denote a vector of the Pauli matrices. + * + * This function effects unitary + * @f[ + \hat{R}_{\bar{n}}(\theta) + = + \exp \left( + - \iu \frac{\theta}{2} + \bar{n} \cdot \vec{\sigma} + \right) + * @f] + * upon the target qubit. Explicitly, + * @f[ + \hat{R}_{\bar{n}}(\theta) + \equiv + \begin{pmatrix} + \cos\left( \frac{\theta}{2} \right) - \iu \, \bar{n}_z \sin\left( \frac{\theta}{2} \right) + & + - \, (\bar{n}_y + \bar{n}_x \, \iu ) \sin\left( \frac{\theta}{2} \right) + \\ + (\bar{n}_y - \bar{n}_x \, \iu ) \sin\left( \frac{\theta}{2} \right) + & + \cos\left( \frac{\theta}{2} \right) + \iu \, \bar{n}_z \sin\left( \frac{\theta}{2} \right) + \end{pmatrix} + * @f] + * where + * @f[ + \bar{n}_i + = + \frac{\vec{n}_i}{\| \vec{n} \|_2} + = + \frac{\vec{n}_i}{ \sqrt{ {\vec{n}_x}^2 + {\vec{n}_y}^2 + {\vec{n}_z}^2 } }. + * @f] + * + * @equivalences + * - Assuming @f$ \| \vec{n} \|_2 \ne 0 @f$, this function is agnostic to the normalisation + * of the axis vector. + * ``` + applyRotateAroundAxis(qureg, target, angle, x, y, z); + applyRotateAroundAxis(qureg, target, angle, 5*x,5*y,5*z); // equivalent + * ``` + * - This function is entirely equivalent to preparing @f$ \hat{R}_{\bar{n}}(\theta) @f$ + * as a CompMatr1 and effecting it upon the state via applyCompMatr1(). + * - This function is both more accurate and efficient than equivalently instantiating a + * three-term PauliStrSum @f$ \hat{H} = \bar{n} \cdot \vec{\sigma}@f$ and effecting + * @f$ \exp \left(\iu \alpha \hat{H} \right) @f$ via applyTrotterizedPauliStrSumGadget() + * with @f$ \alpha = - \theta/2 @f$ and very many repetitions. + * - Passing @p angle=0 is equivalent to effecting the identity, leaving the state unchanged. + */ +void applyRotateAroundAxis(Qureg qureg, int target, qreal angle, qreal axisX, qreal axisY, qreal axisZ); -/// @notdoced +/// @notyetdoced void applyControlledRotateAroundAxis(Qureg qureg, int ctrl, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ); -/// @notdoced +/// @notyetdoced void applyMultiControlledRotateAroundAxis(Qureg qureg, int* ctrls, int numCtrls, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ); -/// @notdoced +/// @notyetdoced +/// @see +/// - applyRotateAroundAxis() +/// - applyMultiStateControlledCompMatr1() void applyMultiStateControlledRotateAroundAxis(Qureg qureg, int* ctrls, int* states, int numCtrls, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ); @@ -1391,59 +1706,67 @@ void applyMultiStateControlledRotateAroundAxis(Qureg qureg, int* ctrls, int* sta #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledRotateX() void applyMultiControlledRotateX(Qureg qureg, std::vector controls, int target, qreal angle); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledRotateY() void applyMultiControlledRotateY(Qureg qureg, std::vector controls, int target, qreal angle); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledRotateZ() void applyMultiControlledRotateZ(Qureg qureg, std::vector controls, int target, qreal angle); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledRotateX() void applyMultiStateControlledRotateX(Qureg qureg, std::vector controls, std::vector states, int target, qreal angle); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledRotateY() void applyMultiStateControlledRotateY(Qureg qureg, std::vector controls, std::vector states, int target, qreal angle); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledRotateZ() void applyMultiStateControlledRotateZ(Qureg qureg, std::vector controls, std::vector states, int target, qreal angle); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledRotateAroundAxis() void applyMultiControlledRotateAroundAxis(Qureg qureg, std::vector ctrls, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledRotateAroundAxis() void applyMultiStateControlledRotateAroundAxis(Qureg qureg, std::vector ctrls, std::vector states, int targ, qreal angle, qreal axisX, qreal axisY, qreal axisZ); @@ -1465,23 +1788,84 @@ extern "C" { #endif -/// @notdoced +/// @notyetdoced +/// @see +/// - multiplyCompMatr1() +/// - applyPauliGadget() void multiplyPauliGadget(Qureg qureg, PauliStr str, qreal angle); -/// @notdoced +/** @notyetdoced + * + * @formulae + * Let @f$ \hat{\sigma} = @f$ @p str and @f$ \theta = @f$ @p angle. + * + * This function effects unitary + * @f[ + R_{\hat{\sigma}}(\theta) = \exp \left( - \iu \, \frac{\theta}{2} \, \hat{\sigma} \right), + * @f] + * which affects only the qubits for which @f$ \hat{\sigma} @f$ is not the identity + * Pauli. As such, this effects a multi-qubit rotation around an arbitrary Pauli string. + * + * @equivalences + * - Because @f$ R_{\hat{\sigma}}(\theta) @f$ satisfies + * @f[ + R_{\hat{\sigma}}(\theta) \equiv + \cos\left( \frac{\theta}{2} \right) \, \id + - \iu \sin\left( \frac{\theta}{2} \right) \, \hat{\sigma}, + * @f] + * this function is equivalent to (but much faster than) effecting @f$ \hat{\sigma} @f$ + * upon a clone which is subsequently superposed. + * ``` + // prepare |temp> = str |qureg> + Qureg temp = createCloneQureg(qureg); + applyPauliStr(temp, str); + + // set |qureg> = cos(theta/2) |qureg> - i sin(theta/2) str |qureg> + setQuregToSuperposition(cos(theta/2), qureg, - 1.0i * sin(theta/2), temp, 0, temp); + * ``` + * - When @p str contains only @f$ \hat{Z} @f$ or @f$ \id @f$ Paulis, this function will + * automatically invoke applyPhaseGadget() which leverages an optimised implementation. + * - When @p str contains only @f$ \id @f$ Paulis, this function merely effects a change + * of global phase upon statevectors of @f$ -\theta/2 @f$, leaving density matrices + * unchanged. + * ``` + qcomp factor = cexp(- theta / 2 * 1.i); + setQuregToSuperposition(factor, qureg, 0,qureg,0,qureg); + * ``` + * + * @myexample + * ``` + Qureg qureg = createQureg(10); + qreal theta = 3.14; + + // verbosely + int numPaulis = 4; + char* paulis = "XYIZ"; + int targets[] = {0,1,5,7}; + PauliStr str = getPauliStr(paulis, targets, numPaulis); + applyPauliGadget(qureg, str, angle); + + // concisely + applyPauliGadget(qureg, getInlinePauliStr("XYZ",{0,1,7}), theta); + * ``` + * - Passing @p angle=0 is equivalent to effecting the identity, leaving the state unchanged. + */ void applyPauliGadget(Qureg qureg, PauliStr str, qreal angle); -/// @notdoced +/// @notyetdoced void applyControlledPauliGadget(Qureg qureg, int control, PauliStr str, qreal angle); -/// @notdoced +/// @notyetdoced void applyMultiControlledPauliGadget(Qureg qureg, int* controls, int numControls, PauliStr str, qreal angle); -/// @notdoced +/// @notyetdoced +/// @see +/// - applyPauliGadget() +/// - applyMultiStateControlledCompMatr1() void applyMultiStateControlledPauliGadget(Qureg qureg, int* controls, int* states, int numControls, PauliStr str, qreal angle); @@ -1493,17 +1877,19 @@ void applyMultiStateControlledPauliGadget(Qureg qureg, int* controls, int* state #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledPauliGadget() void applyMultiControlledPauliGadget(Qureg qureg, std::vector controls, PauliStr str, qreal angle); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledPauliGadget() void applyMultiStateControlledPauliGadget(Qureg qureg, std::vector controls, std::vector states, PauliStr str, qreal angle); @@ -1525,35 +1911,96 @@ extern "C" { #endif -/// @notdoced +/// @notyetdoced +/// @see +/// - multiplyCompMatr1() +/// - applyPhaseGadget void multiplyPhaseGadget(Qureg qureg, int* targets, int numTargets, qreal angle); -/// @notdoced +/** @notyetdoced + * + * @formulae + * + * Let @f$ \vec{t} = @f$ @p targets and @f$ \theta = @f$ @p angle. + * + * This function effects diagonal unitary + * @f[ + R_{\hat{Z}}(\theta) = \exp \left( - \iu \, \frac{\theta}{2} \, \bigotimes_{t \,\in\, \vec{t}} \hat{Z}_t \right). + * @f] + * + * @equivalences + * - This function is equivalent to calling applyPauliGadget() with a PauliStr containing only @f$ \hat{Z} @f$ and @f$ \id @f$. + * This latter function will actually automatically invoke applyPhaseGadget() which has an optimised implementation. + * - This function is equivalent to, albeit much faster than, preparing a DiagMatr with @f$ \pm 1 @f$ elements (depending upon + * the parity of the targeted set bits) and effecting it with applyDiagMatr(). + * - Passing @p angle=0 is equivalent to effecting the identity, leaving the state unchanged. + */ void applyPhaseGadget(Qureg qureg, int* targets, int numTargets, qreal angle); -/// @notdoced +/// @notyetdoced void applyControlledPhaseGadget(Qureg qureg, int control, int* targets, int numTargets, qreal angle); -/// @notdoced +/// @notyetdoced void applyMultiControlledPhaseGadget(Qureg qureg, int* controls, int numControls, int* targets, int numTargets, qreal angle); -/// @notdoced +/// @notyetdoced +/// @see +/// - applyPhaseGadget() +/// - applyMultiStateControlledCompMatr1() void applyMultiStateControlledPhaseGadget(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets, qreal angle); -/// @notdoced +/** @notyetdoced + * + * This function is a mere alias of applyPauliZ(), meaningfully differing only for many targets. + */ void applyPhaseFlip(Qureg qureg, int target); -/// @notdoced +/** @notyetdoced + * + * @formulae + * + * Let @f$ \theta = @f$ @p angle. This function effects diagonal unitary + * + * @f[ + \hat{U}(\theta) = \begin{pmatrix} 1 & 0 \\ 0 & e^{\iu \theta} \end{pmatrix} + * @f] + * upon the @p target qubit. + * + * @equivalences + * - This function is equivalent to, albeit much faster than, a Z-axis rotation with + * an adjustment to the global phase (which is redundant upon density matrices). + * @f[ + * \hat{U}(\theta) \equiv \hat{R}_z(\theta) \cdot e^{\iu \frac{\theta}{2}} \hat{\id} + * @f] + * ``` + applyRotateZ(qureg, target, angle); + applyPauliGadget(qureg, getPauliStr("I"), angle); // global phase + * ``` + * - Passing @p angle=0 is equivalent to effecting the identity, leaving the state unchanged. + */ void applyPhaseShift(Qureg qureg, int target, qreal angle); -/** Applies a two-qubit phase flip upon @p qubit1 and @p qubit2 of @p qureg. +/** @notyetdoced + * + * Applies a two-qubit phase flip upon qubits @p target1 and @p target2 of @p qureg. + * + * @formulae + * + * This function flips the sign of all computational basis states for which + * the targeted qubits are in state @f$ \ket{1}\ket{1} @f$. This is equivalent + * to the diagonal unitary + * + * @f[ + \hat{U}(\theta) = \begin{pmatrix} 1 \\ & 1 \\ & & 1 \\ & & & -1 \end{pmatrix}, + * @f] + * effected upon the target qubits. * * @diagram * @dot @@ -1577,12 +2024,41 @@ digraph { } * @enddot * - * @notdoced + * @equivalences + * - The target qubits are interchangeable, ergo + * ``` + applyTwoQubitPhaseFlip(qureg, target1, target2); + applyTwoQubitPhaseFlip(qureg, target2, target1); // equivalent + * ``` + * - This function is entirely equivalent to a controlled Pauli-Z unitary (or a hypothetical + * controlled variant of applyPhaseFlip()) with either target qubit substituted for the control qubit. + * ``` + applyControlledPauliZ(qureg, target1, target2); + * ``` + * - This function is faster and more accurate than, but otherwise equivalent to, a two-qubit phase shift + * with angle @f$ = \pi @f$. + * ``` + applyTwoQubitPhaseShift(qureg, target1, target2, 3.141592653); // approx equiv + * ``` */ -void applyTwoQubitPhaseFlip( Qureg qureg, int target1, int target2); +void applyTwoQubitPhaseFlip(Qureg qureg, int target1, int target2); -/** Applies a two-qubit phase flip upon @p qubit1 and @p qubit2 of @p qureg. +/** @notyetdoced + * + * Applies a two-qubit phase shift upon qubits @p target1 and @p target2 of @p qureg. + * + * @formulae + * + * Let @f$ \theta = @f$ @p angle. + * This function multiplies factor @f$ e^{\iu \theta} @f$ upon all computational basis states + * for which the targeted qubits are in state @f$ \ket{1}\ket{1} @f$. This is equivalent + * to the diagonal unitary + * + * @f[ + \hat{U}(\theta) = \begin{pmatrix} 1 \\ & 1 \\ & & 1 \\ & & & e^{\iu \theta} \end{pmatrix}, + * @f] + * effected upon the target qubits. * * @diagram * @dot @@ -1608,16 +2084,93 @@ digraph { } * @enddot * - * @notdoced + * @equivalences + * - The target qubits are interchangeable, ergo + * ``` + applyTwoQubitPhaseShift(qureg, target1, target2, angle); + applyTwoQubitPhaseShift(qureg, target2, target1, angle); // equivalent + * ``` + * - This function is equivalent to a controlled variant of applyPhaseShift(), treating + * either target qubit as the control qubit. + * - This function generalises applyTwoQubitPhaseFlip() to arbitrary changes in phase. + * - Passing @p angle=0 is equivalent to effecting the identity, leaving the state unchanged. */ void applyTwoQubitPhaseShift(Qureg qureg, int target1, int target2, qreal angle); -/// @notdoced +/** @notyetdoced + * + * @formulae + * + * This function flips the sign of all computational basis states for which + * the targeted qubits are all in state @f$ \ket{1} @f$. This is equivalent + * to the diagonal unitary + * @f[ + \hat{U}(\theta) = \begin{pmatrix} 1 \\ & \ddots \\ & & 1 \\ & & & -1 \end{pmatrix}, + * @f] + * effected upon the target qubits. + * + * @equivalences + * - The ordering of @p targets has no affect on the effected operation. + * - This function is entirely equivalent to a multi-controlled Pauli-Z unitary (or a hypothetical + * many-controlled variant of applyPhaseFlip()) with all but one arbitrary target qubit becoming + * control qubits. + * ``` + applyMultiControlledPauliZ(qureg, targets, numTargets-1, targets[0]); + * ``` + * - This function is faster and more accurate than, but otherwise equivalent to, a multi-qubit phase shift + * with angle @f$ = \pi @f$. + * ``` + applyMultiQubitPhaseShift(qureg, targets, numTargets, 3.141592653); // approx equiv + * ``` + */ void applyMultiQubitPhaseFlip(Qureg qureg, int* targets, int numTargets); -/// @notdoced +/** @notyetdoced + * + * @formulae + * + * Let @f$ \theta = @f$ @p angle. + * This function multiplies factor @f$ e^{\iu \theta} @f$ upon all computational basis states + * for which all targeted qubits are in state @f$ \ket{1} @f$. This is equivalent + * to the diagonal unitary + * @f[ + \hat{U}(\theta) = \begin{pmatrix} 1 \\ & \ddots \\ & & 1 \\ & & & e^{\iu \theta} \end{pmatrix}, + * @f] + * effected upon the target qubits. + * + * @diagram + * @dot +digraph { + rankdir=LR; + layout=neato; + node [fontsize=10, fontname="Menlo"]; + edge [dir=none]; + + topWireL [shape=plaintext, label="target1", pos="0,.5!"]; + topWireM [shape=point, label="", width=.1, pos=".75,.5!"] + topWireR [shape=plaintext, label="", pos="1.5,.5!"]; + + botWireL [shape=plaintext, label="target2", pos="0,0!"]; + botWireM [shape=point, label="", width=.1, pos=".75,0!"]; + botWireR [shape=plaintext, label="", pos="1.5,0!"]; + + topWireL -> topWireR; + botWireL -> botWireR; + botWireM -> topWireM; + + angle [shape=plaintext, label="θ", pos=".85,-.2!"]; +} + * @enddot + * + * @equivalences + * - The ordering of @p targets has no affect on the effected operation. + * - This function is equivalent to a multi-controlled variant of applyPhaseShift(), treating all + * but one arbitrary target qubit as control qubits. + * - This function generalises applyMultiQubitPhaseFlip() to arbitrary changes in phase. + * - Passing @p angle=0 is equivalent to effecting the identity, leaving the state unchanged. + */ void applyMultiQubitPhaseShift(Qureg qureg, int* targets, int numTargets, qreal angle); @@ -1629,52 +2182,59 @@ void applyMultiQubitPhaseShift(Qureg qureg, int* targets, int numTargets, qreal #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see multiplyPhaseGadget() void multiplyPhaseGadget(Qureg qureg, std::vector targets, qreal angle); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyPhaseGadget() void applyPhaseGadget(Qureg qureg, std::vector targets, qreal angle); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyControlledPhaseGadget() void applyControlledPhaseGadget(Qureg qureg, int control, std::vector targets, qreal angle); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledPhaseGadget() void applyMultiControlledPhaseGadget(Qureg qureg, std::vector controls, std::vector targets, qreal angle); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledPhaseGadget() void applyMultiStateControlledPhaseGadget(Qureg qureg, std::vector controls, std::vector states, std::vector targets, qreal angle); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiQubitPhaseFlip() void applyMultiQubitPhaseFlip(Qureg qureg, std::vector targets); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiQubitPhaseShift() void applyMultiQubitPhaseShift(Qureg qureg, std::vector targets, qreal angle); @@ -1696,13 +2256,63 @@ extern "C" { #endif -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated +/// @see multiplyCompMatr1() void multiplyPauliStrSum(Qureg qureg, PauliStrSum sum, Qureg workspace); -/// @notdoced -/// @nottested +/** @notyetdoced + * @notyettested + * + * @formulae + * + * Let @f$ \hat{H} = @f$ @p sum and @f$ \theta = @f$ @p angle. This function approximates the action of + * @f[ + \exp \left(\iu \, \theta \, \hat{H} \right) + * @f] + * via a Trotter-Suzuki decomposition of the specified @p order and number of repetitions (@p reps). + * + * + * To be precise, let @f$ r = @f$ @p reps and assume @p sum is composed of + * @f$ T @f$-many terms of the form + * @f[ + \hat{H} = \sum\limits_j^T c_j \, \hat{\sigma}_j + * @f] + * where @f$ c_j @f$ is the (necessarily real) coefficient of the @f$ j @f$-th PauliStr @f$ \hat{\sigma}_j @f$. + * + * - When @p order=1, this function performs first-order Trotterisation, whereby + * @f[ + \exp(\iu \, \theta \, \hat{H} ) + \approx + \prod\limits^{r} + \prod\limits_{j=1}^{T} + \exp \left( \iu \, \frac{\theta \, c_j}{r} \, \hat\sigma_j \right). + * @f] + * - When @p order=2, this function performs the lowest order "symmetrized" Suzuki decomposition, whereby + * @f[ + \exp(\iu \, \theta \, \hat{H} ) + \approx + \prod\limits^{r} \left[ + \prod\limits_{j=1}^{T} \exp \left( \iu \frac{\theta \, c_j}{2 \, r} \hat\sigma_j \right) + \prod\limits_{j=T}^{1} \exp \left( \iu \frac{\theta \, c_j}{2 \, r} \hat\sigma_j \right) + \right]. + * @f] + * - Greater, even values of @p order (denoted by symbol @f$ n @f$) invoke higher-order symmetrized decompositions + * @f$ S[\theta,n,r] @f$. Letting @f$ p = \left( 4 - 4^{1/(n-1)} \right)^{-1} @f$, these satisfy + * @f{align*} + S[\theta, n, 1] &= + \left( \prod\limits^2 S[p \, \theta, n-2, 1] \right) + S[ (1-4p)\,\theta, n-2, 1] + \left( \prod\limits^2 S[p \, \theta, n-2, 1] \right), + \\ + S[\theta, n, r] &= + \prod\limits^{r} S\left[\frac{\theta}{r}, n, 1\right]. + * @f} + * + * > These formulations are taken from 'Finding Exponential Product Formulas + * > of Higher Orders', Naomichi Hatano and Masuo Suzuki (2005) (arXiv). + */ void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle, int order, int reps); @@ -1728,23 +2338,26 @@ extern "C" { #endif -/// @notdoced +/// @notyetdoced +/// @see multiplyCompMatr1() void multiplyMultiQubitNot(Qureg qureg, int* targets, int numTargets); -/// @notdoced +/// @notyetdoced void applyMultiQubitNot(Qureg qureg, int* targets, int numTargets); -/// @notdoced +/// @notyetdoced void applyControlledMultiQubitNot(Qureg qureg, int control, int* targets, int numTargets); -/// @notdoced +/// @notyetdoced void applyMultiControlledMultiQubitNot(Qureg qureg, int* controls, int numControls, int* targets, int numTargets); -/// @notdoced +/// @notyetdoced +/// @see +/// - applyMultiStateControlledCompMatr1() void applyMultiStateControlledMultiQubitNot(Qureg qureg, int* controls, int* states, int numControls, int* targets, int numTargets); @@ -1756,38 +2369,43 @@ void applyMultiStateControlledMultiQubitNot(Qureg qureg, int* controls, int* sta #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see multiplyMultiQubitNot() void multiplyMultiQubitNot(Qureg qureg, std::vector targets); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiQubitNot() void applyMultiQubitNot(Qureg qureg, std::vector targets); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyControlledMultiQubitNot() void applyControlledMultiQubitNot(Qureg qureg, int control, std::vector targets); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiControlledMultiQubitNot() void applyMultiControlledMultiQubitNot(Qureg qureg, std::vector controls, std::vector targets); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiStateControlledMultiQubitNot() void applyMultiStateControlledMultiQubitNot(Qureg qureg, std::vector controls, std::vector states, std::vector targets); @@ -1809,33 +2427,33 @@ extern "C" { #endif -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated int applyQubitMeasurement(Qureg qureg, int target); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated int applyQubitMeasurementAndGetProb(Qureg qureg, int target, qreal* probability); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qreal applyForcedQubitMeasurement(Qureg qureg, int target, int outcome); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qindex applyMultiQubitMeasurement(Qureg qureg, int* qubits, int numQubits); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qindex applyMultiQubitMeasurementAndGetProb(Qureg qureg, int* qubits, int numQubits, qreal* probability); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated qreal applyForcedMultiQubitMeasurement(Qureg qureg, int* qubits, int* outcomes, int numQubits); @@ -1847,17 +2465,19 @@ qreal applyForcedMultiQubitMeasurement(Qureg qureg, int* qubits, int* outcomes, #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiQubitMeasurementAndGetProb() qindex applyMultiQubitMeasurementAndGetProb(Qureg qureg, std::vector qubits, qreal* probability); -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyForcedMultiQubitMeasurement() qreal applyForcedMultiQubitMeasurement(Qureg qureg, std::vector qubits, std::vector outcomes); @@ -1879,13 +2499,13 @@ extern "C" { #endif -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void applyQubitProjector(Qureg qureg, int target, int outcome); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void applyMultiQubitProjector(Qureg qureg, int* qubits, int* outcomes, int numQubits); @@ -1897,10 +2517,11 @@ void applyMultiQubitProjector(Qureg qureg, int* qubits, int* outcomes, int numQu #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyMultiQubitProjector() void applyMultiQubitProjector(Qureg qureg, std::vector qubits, std::vector outcomes); @@ -1922,13 +2543,13 @@ extern "C" { #endif -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void applyQuantumFourierTransform(Qureg qureg, int* targets, int numTargets); -/// @notdoced -/// @notvalidated +/// @notyetdoced +/// @notyetvalidated void applyFullQuantumFourierTransform(Qureg qureg); @@ -1940,10 +2561,11 @@ void applyFullQuantumFourierTransform(Qureg qureg); #ifdef __cplusplus -/// @nottested -/// @notvalidated -/// @notdoced -/// @cpponly +/// @notyettested +/// @notyetvalidated +/// @notyetdoced +/// @cppvectoroverload +/// @see applyQuantumFourierTransform() void applyQuantumFourierTransform(Qureg qureg, std::vector targets); diff --git a/quest/include/paulis.h b/quest/include/paulis.h index 55f48c485..1d08169f2 100644 --- a/quest/include/paulis.h +++ b/quest/include/paulis.h @@ -49,7 +49,7 @@ */ -/// @notdoced +/// @notyetdoced typedef struct { // represent Pauli strings as base-4 numerals, split into their @@ -61,7 +61,7 @@ typedef struct { } PauliStr; -/// @notdoced +/// @notyetdoced typedef struct { qindex numTerms; @@ -113,8 +113,14 @@ typedef struct { extern "C" { #endif - /// @ingroup paulis_create - /// @notdoced + /** @ingroup paulis_create + * @notyetdoced + * + * @see + * - reportPauliStr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.c) or + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.cpp) examples + */ PauliStr getPauliStr(const char* paulis, int* indices, int numPaulis); #ifdef __cplusplus @@ -134,26 +140,48 @@ extern "C" { // {0,3,1} are valid std::string instances, causing overload ambiguity. Blegh! - /// @ingroup paulis_create - /// @notdoced + /** @ingroup paulis_create + * @notyetdoced + * + * @see + * - reportPauliStr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.c) or + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.cpp) examples + */ PauliStr getPauliStr(int* paulis, int* indices, int numPaulis); - /// @ingroup paulis_create - /// @notdoced - /// @cpponly + /** @ingroup paulis_create + * @notyetdoced + * @cpponly + * + * @see + * - getPauliStr() + * - reportPauliStr() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.cpp) examples + */ PauliStr getPauliStr(std::string paulis, int* indices, int numPaulis); - /// @ingroup paulis_create - /// @notdoced - /// @cpponly + /** @ingroup paulis_create + * @notyetdoced + * @cpponly + * + * @see + * - reportPauliStr() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.cpp) examples + */ PauliStr getPauliStr(std::string paulis, std::vector indices); - /// @ingroup paulis_create - /// @notdoced - /// @cpponly + /** @ingroup paulis_create + * @notyetdoced + * @cpponly + * + * @see + * - reportPauliStr() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.cpp) examples + */ PauliStr getPauliStr(std::string paulis); @@ -196,9 +224,15 @@ extern "C" { // spoofing above macro as function to doc #if 0 - /// @ingroup paulis_create - /// @notdoced - /// @macrodoc + /** @ingroup paulis_create + * @notyetdoced + * @macrodoc + * + * @see + * - reportPauliStr() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.cpp)examples + */ PauliStr getInlinePauliStr(const char* paulis, { list }); #endif @@ -219,23 +253,47 @@ extern "C" { #endif - /// @ingroup paulis_create - /// @notdoced + /** @ingroup paulis_create + * @notyetdoced + * + * @see + * - reportPauliStrSum() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.c) or + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.cpp) examples + */ PauliStrSum createPauliStrSum(PauliStr* strings, qcomp* coeffs, qindex numTerms); - /// @ingroup paulis_create - /// @notdoced + /** @ingroup paulis_create + * @notyetdoced + * + * @see + * - reportPauliStrSum() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.c) or + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.cpp) examples + */ PauliStrSum createInlinePauliStrSum(const char* str); - /// @ingroup paulis_create - /// @notdoced + /** @ingroup paulis_create + * @notyetdoced + * + * @see + * - reportPauliStrSum() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.c) or + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.cpp) examples + */ PauliStrSum createPauliStrSumFromFile(const char* fn); - /// @ingroup paulis_create - /// @notdoced + /** @ingroup paulis_create + * @notyetdoced + * + * @see + * - reportPauliStrSum() + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.c) or + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.cpp) examples + */ PauliStrSum createPauliStrSumFromReversedFile(const char* fn); @@ -248,27 +306,51 @@ extern "C" { #ifdef __cplusplus - /// @ingroup paulis_create - /// @notdoced - /// @cpponly + /** @ingroup paulis_create + * @notyetdoced + * @cpponly + * + * @see + * - createPauliStrSum() + * - reportPauliStrSum() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.cpp) examples + */ PauliStrSum createPauliStrSum(std::vector strings, std::vector coeffs); - /// @ingroup paulis_create - /// @notdoced - /// @cpponly + /** @ingroup paulis_create + * @notyetdoced + * @cpponly + * + * @see + * - createInlinePauliStrSum() + * - reportPauliStrSum() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.cpp) examples + */ PauliStrSum createInlinePauliStrSum(std::string str); - /// @ingroup paulis_create - /// @notdoced - /// @cpponly + /** @ingroup paulis_create + * @notyetdoced + * @cpponly + * + * @see + * - createPauliStrSumFromFile() + * - reportPauliStrSum() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.cpp) examples + */ PauliStrSum createPauliStrSumFromFile(std::string fn); - /// @ingroup paulis_create - /// @notdoced - /// @cpponly + /** @ingroup paulis_create + * @notyetdoced + * @cpponly + * + * @see + * - createPauliStrSumFromReversedFile() + * - reportPauliStrSum() + * - [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/initialising_paulis.cpp) examples + */ PauliStrSum createPauliStrSumFromReversedFile(std::string fn); @@ -288,7 +370,7 @@ extern "C" { /// @ingroup paulis_destroy - /// @notdoced + /// @notyetdoced void destroyPauliStrSum(PauliStrSum sum); @@ -309,14 +391,25 @@ extern "C" { #endif - /// @ingroup paulis_reporters - /// @notdoced - /// @nottested + /** @ingroup paulis_reporters + * @notyetdoced + * @notyettested + * + * @see + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_paulis.c) or + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_paulis.cpp) examples + */ void reportPauliStr(PauliStr str); - /// @ingroup paulis_reporters - /// @notdoced - /// @nottested + + /** @ingroup paulis_reporters + * @notyetdoced + * @notyettested + * + * @see + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_paulis.c) or + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_paulis.cpp) examples + */ void reportPauliStrSum(PauliStrSum str); diff --git a/quest/include/precision.h b/quest/include/precision.h index 0214daf6f..cfd150855 100644 --- a/quest/include/precision.h +++ b/quest/include/precision.h @@ -38,7 +38,7 @@ // spoofing above macro as const to doc #if 0 - /// @notdoced + /// @notyetdoced /// @macrodoc typedef long long int INDEX_TYPE; @@ -64,7 +64,7 @@ // spoofing above macro as typedef to doc #if 0 - /// @notdoced + /// @notyetdoced /// @macrodoc typedef long long unsigned int PAULI_MASK_TYPE; @@ -98,11 +98,11 @@ // spoofing above macros as typedefs and consts to doc #if 0 - /// @notdoced + /// @notyetdoced /// @macrodoc const int FLOAT_PRECISION = 2; - /// @notdoced + /// @notyetdoced /// @macrodoc typedef double int FLOAT_TYPE; @@ -146,7 +146,7 @@ // spoofing above macros as typedefs and consts to doc #if 0 - /// @notdoced + /// @notyetdoced /// @macrodoc const qreal DEFAULT_VALIDATION_EPSILON = 1E-12; @@ -172,7 +172,7 @@ // spoofing above macros as typedefs and consts to doc #if 0 - /// @notdoced + /// @notyetdoced /// @macrodoc const char* QREAL_FORMAT_SPECIFIER = "%.14g"; diff --git a/quest/include/qureg.h b/quest/include/qureg.h index 1ef8a43c0..39d744f0a 100644 --- a/quest/include/qureg.h +++ b/quest/include/qureg.h @@ -45,7 +45,7 @@ extern "C" { */ -/// @notdoced +/// @notyetdoced typedef struct { // deployment configuration @@ -90,27 +90,297 @@ typedef struct { */ -/// @notdoced +/** Creates a statevector containing @p numQubits qubits, with automatically chosen deployments, + * initialised in the zero state. + * + * The chosen deployments (multithreading, GPU-acceleration and distribution) are informed by + * which facilities are compiled, available at runtime, beneficial for the specified Qureg size, + * and whether the necessary additional memory structures can fit in accelerators and buffers. + * + * @par State + * Let @f$ N = @f$ @p numQubits. The returned Qureg contains @f$ 2^N @f$ amplitudes, each represented + * by a @c qcomp, initialised to state + * @f[ + \ket{0}^{\otimes N} + \;\; = \;\; + \{ 1, \, 0, \, 0, \, \dots, \, 0 \}. + * @f] + * + * @par Memory + * The total allocated memory will depend upon the automatically chosen deployments, since + * use of GPU-acceleration requires persistent device memory and distribution necessitates + * allocating communication buffers. See createCustomQureg() for more information. + * + * @equivalences + * - This function is equivalent to calling createCustomQureg(), passing @c isDensMatr=0 and @c -1 + * for all deployments to automate them. + * ``` + Qureg qureg = createCustomQureg(numQubits, 0, -1, -1, -1); + * ``` + * @myexample + * ``` + Qureg qureg = createQureg(30); + reportQuregParams(qureg); + * ``` + * @param[in] numQubits the number of qubits in the output Qureg. + * @returns A new Qureg instance. + * @throws @validationerror + * - if @p numQubits < 1 + * - if the Qureg dimensions would overflow the @c qindex type. + * - if the total Qureg memory would overflow the @c size_t type. + * - if the system contains insufficient RAM (or VRAM) to store the Qureg in any deployment. + * - if any memory allocation unexpectedly fails. + * @notyetvalidated + * @see + * - createDensityQureg() to create a density matrix which can additionally undergo decoherence. + * - createForcedQureg() to create a statevector which is forced to make use of all available deployments. + * - createCustomQureg() to explicitly set the used deployments. + * @author Tyson Jones + */ Qureg createQureg(int numQubits); -/// @notdoced +/** Creates a density matrix containing @p numQubits qubits, with automatically chosen deployments, + * initialised in the zero state. + * + * The chosen deployments (multithreading, GPU-acceleration and distribution) are informed by + * which facilities are compiled, available at runtime, beneficial for the specified Qureg size, + * and whether the necessary additional memory structures can fit in accelerators and buffers. + * + * @par State + * Let @f$ N = @f$ @p numQubits. The returned Qureg contains @f$ 2^N \times 2^N @f$ amplitudes, each + * represented by a @c qcomp, initialised to state + * @f[ + \ket{0}\bra{0}^{\otimes N} + \;\; = \;\; + \begin{pmatrix} + 1 & 0 & \dots \\ + 0 & 0 & \\ + \vdots & & \ddots + \end{pmatrix}. + * @f] + * + * @par Memory + * A density matrix contains _square_ as many amplitudes as the equal-dimension statevector. + * The total allocated memory will depend upon the automatically chosen deployments, since + * use of GPU-acceleration requires persistent device memory and distribution necessitates + * allocating communication buffers. See createCustomQureg() for more information. + * + * @equivalences + * - This function is equivalent to calling createCustomQureg(), passing @c isDensMatr=1 and @c -1 + * for all deployments to automate them. + * ``` + Qureg qureg = createCustomQureg(numQubits, 1, -1, -1, -1); + * ``` + * @myexample + * ``` + Qureg qureg = createDensityQureg(15); + reportQuregParams(qureg); + * ``` + * @param[in] numQubits the number of qubits in the output Qureg. + * @returns A new Qureg instance. + * @throws @validationerror + * - if @p numQubits < 1 + * - if the Qureg dimensions would overflow the @c qindex type. + * - if the total Qureg memory would overflow the @c size_t type. + * - if the system contains insufficient RAM (or VRAM) to store the Qureg in any deployment. + * - if any memory allocation unexpectedly fails. + * @notyetvalidated + * @see + * - createQureg() to create a quadratically-smaller statevector Qureg which cannot undergo decoherence. + * - createForcedDensityQureg() to create a density matrix which is forced to make use of all available deployments. + * - createCustomQureg() to explicitly set the used deployments. + * @author Tyson Jones + */ Qureg createDensityQureg(int numQubits); -/// @notdoced +/** @notyetdoced + * + * @equivalences + * - This function is equivalent to calling createCustomQureg(), passing @c isDensMatr=0 and all + * deployments enabled by the QuEST environment. + * ``` + QuESTEnv env = getQuESTEnv(); + Qureg qureg = createCustomQureg( + numQubits, 0, + env.isDistributed, + env.isGpuAccelerated, + env.isMultithreaded); + * ``` + */ Qureg createForcedQureg(int numQubits); -/// @notdoced +/** @notyetdoced + * + * @equivalences + * - This function is equivalent to calling createCustomQureg(), passing @c isDensMatr=1 and all + * deployments enabled by the QuEST environment. + * ``` + QuESTEnv env = getQuESTEnv(); + Qureg qureg = createCustomQureg( + numQubits, 1, + env.isDistributed, + env.isGpuAccelerated, + env.isMultithreaded); + * ``` + */ Qureg createForcedDensityQureg(int numQubits); -/// @notdoced +/** Creates a statevector or density matrix with the specified deployments, initialised + * in the zero state. This function is an alternative to createQureg() and createDensityQureg() + * which permits explicitly forcing, disabling, or automating particular deployments. + * + * @par State + * Parameters @p numQubits and @p isDensMatr respectively inform the dimension of the + * Qureg, and whether the Qureg is a density matrix or statevector. + * + * Let @f$ N = @f$ @p numQubits. + * - When @p isDensMatr=0, the returned statevector contains @f$ 2^N @f$ amplitudes, + * initialised to state + * @f[ + \ket{0}^{\otimes N} + \;\; = \;\; + \{ 1, \, 0, \, 0, \, \dots, \, 0 \}. + * @f] + * - When @p isDensMatr=1, the returned density matrix contains @f$ 2^{N}\times 2^{N} @f$ amplitudes, + * initialised to state + * @f[ + \ket{0}\bra{0}^{\otimes N} + \;\; = \;\; + \begin{pmatrix} + 1 & 0 & \dots \\ + 0 & 0 & \\ + \vdots & & \ddots + \end{pmatrix}. + * @f] + * + * @par Deployments + * The remaining parameters decide the deployments used to accelerate the Qureg in subsequent + * simulation, and the associated additional memory allocations. + * - @p useDistrib indicates whether (@c =1) or not (@c =0) to distribute the Qureg's amplitudes + * across all available MPI nodes. This is suitable for Qureg which are too large to fit into a + * single node, and requires allocating an additional communication buffer per-node. When + * @c useDistrib=0 but the QuEST executable is launched in distributed settings, the Qureg + * amplitudes will be duplicated upon every node. + * - @p useGpuAccel indicates whether (@c =1) or not (@c =0) to GPU-accelerate the Qureg, and + * requires allocating additional persistent memory in the GPU VRAM. When combined with + * @c useDistrib=1, every node will allocate both communication buffers _and_ persistent GPU + * memory, and an additional persistent GPU-memory communication buffer. + * - @p useMultithread indicates whether (@c =1) or not (@c =0) to use multithreading when + * subsequently modifying the Qureg with a CPU routine. This requires no additional allocations, + * and typically has no effect when GPU acceleration is also enabled. + * + * The deployment parameters can also be @c -1 to let QuEST choose that parameter, taking into + * account the other forced deployments. While it is always safe to _disable_ a deployment, + * forcing a deployment which is invalid (e.g. because the device has insufficient free memory) + * will throw a validation error. + * + * @par Memory + * The total allocated memory depends on all parameters (_except_ + * @p useMultithread), and the size of the variable-precision @c qcomp used to represent each + * amplitude. This is determined by preprocessor @c FLOAT_PRECISION via + * + *
+ * | @c FLOAT_PRECISION | @c qcomp size (bytes) | + * | --- | --- | + * | 1 | 8 | + * | 2 | 16 | + * | 4 | 16, 20, 32 | + *
+ * where the quad-precision size is platform specific, and is often the size of _two_ + * `long double` primitives. + * + * Let: + * - @f$ N = @f$ @p numQubits + * - @f$ D=2^N @f$ or @f$ =2^{2N} @f$ (the total number of amplitudes in the state) + * - @f$ B = @f$ @c sizeof(qcomp) (the size in bytes) + * - @f$ W @f$ be the total number of distributed nodes (the "world size"). + * + * The allocated CPU memory (RAM) and GPU memory (VRAM) is + * + *
+ * | @p useDistrib | @p useGpuAccel | RAM per node | RAM total | VRAM per node | VRAM total | memory total | + * |---|---|---|---|---|---|---| + * | 0 | 0 | @f$ B \, D @f$ | @f$ W B \, D @f$ | 0 | 0 | @f$ W B \, D @f$ | + * | 0 | 1 | @f$ B \, D @f$ | @f$ W B \, D @f$ | @f$ B \, D @f$ | @f$ W B \, D @f$ | @f$ 2 \, W B \, D @f$ | + * | 1 | 0 | @f$ 2 \, B \, D \, / \, W @f$ | @f$ 2 \, B \, D @f$ | 0 | 0 | @f$ 2 \, B \, D @f$ | + * | 1 | 1 | @f$ 2 \, B \, D \, / \, W @f$ | @f$ 2 \, B \, D @f$ | @f$ 2 \, B \, D \, / \, W @f$ | @f$ 2 \, B \, D @f$ | @f$ 4 \, B \, D @f$ | + *
+ * + * For illustration, using the default @c FLOAT_PRECISION=2 whereby @f$ B = 16 @f$ bytes, the RAM _per node_ + * over varying distributions is: + * + *
+ * | @p isDensMatr | @p numQubits | @f$ W=1 @f$ | @f$ W=2 @f$ | @f$ W=4 @f$ | @f$ W=8 @f$ | @f$ W=16 @f$ | @f$ W=1024 @f$ | + * | ------------- | ------------ | ----------- | ----------- | ----------- | ----------- | ------------ | ------------ | + * | 0 | 20 | 16 MiB | 16 MiB | 8 MiB | 4 MiB | 2 MiB | 32 KiB | + * | 0 | 30 | 16 GiB | 16 GiB | 8 GiB | 4 GiB | 2 GiB | 32 MiB | + * | 0 | 35 | 512 GiB | 512 GiB | 256 GiB | 128 GiB | 64 GiB | 1 GiB | + * | 0 | 40 | 16 TiB | 16 TiB | 8 TiB | 4 TiB | 2 TiB | 32 GiB | + * | 0 | 45 | 512 TiB | 512 TiB | 256 TiB | 128 TiB | 64 TiB | 1 TiB | + * | 0 | 50 | 16 PiB | 16 PiB | 8 PiB | 4 PiB | 2 PiB | 32 TiB | + * | 1 | 10 | 16 MiB | 16 MiB | 8 MiB | 4 MiB | 2 MiB | 32 KiB | + * | 1 | 15 | 16 GiB | 16 GiB | 8 GiB | 4 GiB | 2 GiB | 32 MiB | + * | 1 | 20 | 16 TiB | 16 TiB | 8 TiB | 4 TiB | 2 TiB | 32 GiB | + * | 1 | 25 | 16 PiB | 16 PiB | 8 PiB | 4 PiB | 2 PiB | 32 TiB | + *
+ * + * @constraints + * - Cannot use any deployment which has not been prior enabled during compilation, or disabled by createCustomQuESTEnv(). + * - Cannot distribute @f$ N @f$ qubits over more than @f$ 2^N @f$ nodes (regardless of @p isDensMatr). + * - Cannot distribute when the executable was not launched using MPI (e.g. via @c mpirun). + * - Cannot GPU-accelerate when a GPU is not available at runtime, or has insufficient memory. + * + * @myexample + * ``` + int numQubits = 30; + int isDensMatr = 0; + + int useDistrib = 1; // use distribution + int useMultithread = 0; // don't use multithreading + int useGpuAccel = -1; // automate whether to GPU-accelerate + + Qureg qureg = createCustomQureg( + numQubits, isDensMatr, + useDistrib, useGpuAccel, useMultithread); + + reportQuregParams(qureg); + * ``` + * + * @param[in] numQubits the number of qubits in the output Qureg. + * @param[in] isDensMatr whether the Qureg is a density matrix (@c =1) or statevector (@c =0). + * @param[in] useDistrib whether to force (@c =1), disable (@c =0) or automate (@c =-1) distribution. + * @param[in] useGpuAccel whether to force (@c =1), disable (@c =0) or automate (@c =-1) GPU acceleration. + * @param[in] useMultithread whether to force (@c =1), disable (@c =0) or automate (@c =-1) multithreading. + * @returns A new Qureg instance of the specified dimension and deployments. + * @throws @validationerror + * - if @p numQubits < 1 + * - if @p isDensMatr is not @c 0 or @c 1 + * - if any of @p useDistrib, @p useGpuAccel, @p useMultithread is not @c 0, @c 1 or @c -1. + * - if any of @p useDistrib, @p useGpuAccel, @p useMultithread is forced (@c =1) but is unsupported by the + * active QuESTEnv. This can happen because: + * - the particular deployment was disabled by initCustomQuESTEnv(). + * - the deployment was not enabled during compilation. + * - @p useDistrib=1 but QuEST was not launched by MPI (e.g. via @c mpirun). + * - @p useGpuAccel=1 but a GPU is not accessible at runtime. + * - if @p useDistrib=1 but the Qureg is too small to distribute over the running nodes. + * - if the Qureg dimensions would overflow the @c qindex type. + * - if the total Qureg memory would overflow the @c size_t type. + * - if the system contains insufficient RAM (or VRAM) to store the Qureg. + * - if any memory allocation unexpectedly fails. + * @notyetvalidated + * @see + * - createQureg() to automate deployments (equivalent to passing @c -1). + * - createForcedQureg() to use all available deployments. + * @author Tyson Jones + */ Qureg createCustomQureg(int numQubits, int isDensMatr, int useDistrib, int useGpuAccel, int useMultithread); -/// @notdoced +/// @notyetdoced Qureg createCloneQureg(Qureg qureg); @@ -125,7 +395,7 @@ Qureg createCloneQureg(Qureg qureg); */ -/// @notdoced +/// @notyetdoced void destroyQureg(Qureg qureg); @@ -140,13 +410,23 @@ void destroyQureg(Qureg qureg); */ -/// @notdoced -/// @nottested +/** @notyetdoced + * @notyettested + * + * @see + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_quregs.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_quregs.cpp) examples + */ void reportQuregParams(Qureg qureg); -/// @notdoced -/// @nottested +/** @notyetdoced + * @notyettested + * + * @see + * - [C](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_quregs.c) and + * [C++](https://github.com/QuEST-Kit/QuEST/blob/devel/examples/isolated/reporting_quregs.cpp) examples + */ void reportQureg(Qureg qureg); @@ -166,23 +446,23 @@ void reportQureg(Qureg qureg); */ -/// @notdoced -/// @nottested +/// @notyetdoced +/// @notyettested void syncQuregToGpu(Qureg qureg); -/// @notdoced -/// @nottested +/// @notyetdoced +/// @notyettested void syncQuregFromGpu(Qureg qureg); -/// @notdoced -/// @nottested +/// @notyetdoced +/// @notyettested void syncSubQuregToGpu(Qureg qureg, qindex localStartInd, qindex numLocalAmps); -/// @notdoced -/// @nottested +/// @notyetdoced +/// @notyettested void syncSubQuregFromGpu(Qureg qureg, qindex localStartInd, qindex numLocalAmps); @@ -197,11 +477,11 @@ void syncSubQuregFromGpu(Qureg qureg, qindex localStartInd, qindex numLocalAmps) */ -/// @notdoced +/// @notyetdoced void getQuregAmps(qcomp* outAmps, Qureg qureg, qindex startInd, qindex numAmps); -/// @notdoced +/// @notyetdoced void getDensityQuregAmps(qcomp** outAmps, Qureg qureg, qindex startRow, qindex startCol, qindex numRows, qindex numCols); @@ -232,12 +512,12 @@ void getDensityQuregAmps(qcomp** outAmps, Qureg qureg, qindex startRow, qindex s /// @ingroup qureg_get -/// @notdoced +/// @notyetdoced qcomp getQuregAmp(Qureg qureg, qindex index); /// @ingroup qureg_get -/// @notdoced +/// @notyetdoced qcomp getDensityQuregAmp(Qureg qureg, qindex row, qindex column); @@ -256,18 +536,20 @@ qcomp getDensityQuregAmp(Qureg qureg, qindex row, qindex column); /// @ingroup qureg_get -/// @nottested -/// @notvalidated -/// @notdoced +/// @notyettested +/// @notyetvalidated +/// @notyetdoced /// @cpponly +/// @see getQuregAmps() std::vector getQuregAmps(Qureg qureg, qindex startInd, qindex numAmps); /// @ingroup qureg_get -/// @nottested -/// @notvalidated -/// @notdoced +/// @notyettested +/// @notyetvalidated +/// @notyetdoced /// @cpponly +/// @see getDensityQuregAmps() std::vector> getDensityQuregAmps(Qureg qureg, qindex startRow, qindex startCol, qindex numRows, qindex numCols); diff --git a/quest/include/types.h b/quest/include/types.h index ba172e9b9..c006b02cd 100644 --- a/quest/include/types.h +++ b/quest/include/types.h @@ -87,7 +87,7 @@ typedef INDEX_TYPE qindex; * code, to avoid C & C++ qcomp interoperability issues. */ -/// @notdoced +/// @notyetdoced static inline qcomp getQcomp(qreal re, qreal im) { #if defined(__cplusplus) @@ -169,7 +169,7 @@ static inline qcomp getQcomp(qreal re, qreal im) { // spoofing above macro as const to doc #if 0 - /// @notdoced + /// @notyetdoced /// @macrodoc const int DEFINE_ARITHMETIC_OVERLOADS = 1; @@ -294,47 +294,49 @@ static inline qcomp getQcomp(qreal re, qreal im) { #include - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested extern "C" void reportStr(const char* str); - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested /// @cpponly + /// @see reportStr() void reportStr(std::string str); - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested extern "C" void reportScalar(const char* label, qcomp num); - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested void reportScalar(const char* label, qreal num); - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested /// @cpponly + /// @see reportScalar() void reportScalar(std::string label, qcomp num); - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested /// @cpponly void reportScalar(std::string label, qreal num); #else - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested void reportStr(const char* str); - /// @notdoced - /// @nottested + /// @notyetdoced + /// @notyettested void reportScalar(const char* label, qcomp num); diff --git a/quest/src/core/errors.cpp b/quest/src/core/errors.cpp index b22b48c25..a2c2649ca 100644 --- a/quest/src/core/errors.cpp +++ b/quest/src/core/errors.cpp @@ -381,42 +381,42 @@ void assert_bufferPackerGivenIncreasingQubits(int qubit1, int qubit2, int qubit3 void assert_mixedQuregIsDensityMatrix(Qureg qureg) { if (!qureg.isDensityMatrix) - raiseInternalError("An internal function invoked by mixQuregs() received a statevector where a density matrix was expected."); + raiseInternalError("An internal function invoked by mixQureg() received a statevector where a density matrix was expected."); } void assert_mixedQuregIsStatevector(Qureg qureg) { if (qureg.isDensityMatrix) - raiseInternalError("An internal function invoked by mixQuregs() received a density matrix where a statevector was expected."); + raiseInternalError("An internal function invoked by mixQureg() received a density matrix where a statevector was expected."); } void assert_mixedQuregIsDistributed(Qureg qureg) { if (!qureg.isDistributed) - raiseInternalError("An internal function invoked by mixQuregs() received a non-distributed Qureg where a distributed one was expected."); + raiseInternalError("An internal function invoked by mixQureg() received a non-distributed Qureg where a distributed one was expected."); } void assert_mixedQuregIsLocal(Qureg qureg) { if (qureg.isDistributed) - raiseInternalError("An internal function invoked by mixQuregs() received a distributed Qureg where a non-distributed one was expected."); + raiseInternalError("An internal function invoked by mixQureg() received a distributed Qureg where a non-distributed one was expected."); } void assert_mixedQuregsAreBothOrNeitherDistributed(Qureg a, Qureg b) { if (a.isDistributed != b.isDistributed) - raiseInternalError("An internal function invoked by mixQuregs() received density-matrix Quregs of inconsistent distribution."); + raiseInternalError("An internal function invoked by mixQureg() received density-matrix Quregs of inconsistent distribution."); } void assert_mixQuregTempGpuAllocSucceeded(qcomp* gpuPtr) { if (!mem_isAllocated(gpuPtr)) - raiseInternalError("An internal function invoked by mixQuregs() attempted to allocate temporary GPU memory but failed."); + raiseInternalError("An internal function invoked by mixQureg() attempted to allocate temporary GPU memory but failed."); } void error_mixQuregsAreLocalDensMatrAndDistribStatevec() { - raiseInternalError("An internal function invoked by mixQuregs() received a non-distributed density matrix and a distributed statevector, which is an illegal combination."); + raiseInternalError("An internal function invoked by mixQureg() received a non-distributed density matrix and a distributed statevector, which is an illegal combination."); } void assert_fullStateDiagMatrIsLocal(FullStateDiagMatr matr) { diff --git a/utils/docs/Doxyfile b/utils/docs/Doxyfile index 4a721e1c8..a01ce3d85 100644 --- a/utils/docs/Doxyfile +++ b/utils/docs/Doxyfile @@ -295,18 +295,26 @@ TAB_SIZE = 4 # @} or use a double escape (\\{ and \\}) ALIASES = -ALIASES += "nottested=@warning This function has not yet been unit tested and may contain bugs. Please use with caution!" -ALIASES += "notvalidated=@attention This function's input validation has not yet been tested, so erroneous usage may produce unexpected output. Please use with caution!" -ALIASES += "notdoced=@note Documentation for this function or struct is under construction!" +ALIASES += "notyettested=@warning This function has not yet been unit tested and may contain bugs. Please use with caution!" +ALIASES += "notyetvalidated=@attention This function's input validation has not yet been unit tested, so erroneous usage may produce unexpected output. Please use with caution!" +ALIASES += "notyetdoced=@note Documentation for this function or struct is under construction!" ALIASES += "cpponly=@remark This function is only available in C++." ALIASES += "conly=@remark This function is only available in C." ALIASES += "macrodoc=@note This entity is actually a macro." ALIASES += "neverdoced=@warning This entity is a macro, undocumented directly due to a Doxygen limitation. If you see this doc rendered, contact the devs!" ALIASES += "myexample=@par Example" -ALIASES += "equivalence=@par Equivalences" +ALIASES += "equivalences=@par Equivalences" ALIASES += "constraints=@par Constraints" ALIASES += "formulae=@par Formulae" ALIASES += "diagram=@par Diagram" +ALIASES += "validationerror=error" + +# We are temporarily hiding the @cppvectoroverload functions since they differ +# trivially from the language-agnostic functions (ptr,len vs vector) yet clutter +# the API documentation +## ALIASES += "cppvectoroverload=@remark This function is merely a C++-only overload which accepts a vector(s) in lieu of a pointer(s) and length parameter. All other attributed are unchanged." +ALIASES += "cppvectoroverload=@private" + # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For diff --git a/utils/docs/latex/commands.tex b/utils/docs/latex/commands.tex index 790e1545f..dfd5da5cd 100644 --- a/utils/docs/latex/commands.tex +++ b/utils/docs/latex/commands.tex @@ -15,6 +15,7 @@ \newcommand{\brapsi}{\bra{\psi}} \newcommand{\dmrho}{\mathbf{\rho}} \newcommand{\pstr}{\sigma^{\otimes}} +\newcommand{\iu}{\mathrm{i}} \renewcommand{\poormanscomment}{ The validation epsilon, which should maybe have a special (bold?) symbol } From 49e5ff32568885b0c1da74ef649a56adfd13ea8c Mon Sep 17 00:00:00 2001 From: JPRichings Date: Fri, 23 May 2025 23:22:06 +0100 Subject: [PATCH 09/12] patched overflow in setBit (#623) Since `bitValue` is an `int`, the expression `bitValue << bitIndex` can overflow when `bitIndex` equals/exceeds 32. This is solved by casting `bitValue` into a `qindex` before shifting. (Tyson updated authorlists) --- AUTHORS.txt | 2 ++ README.md | 1 + quest/src/core/bitwise.hpp | 4 +++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/AUTHORS.txt b/AUTHORS.txt index 8089802f5..5b2cdd084 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -44,6 +44,8 @@ Dr Ian Bush [consultant] HPC External contributors: +James Richings + patched overflow in bitwise.hpp logic Luc Jaulmes patched v4's install process using CMake Jakub Adamski diff --git a/README.md b/README.md index bab2d2ff6..260d4b8bb 100644 --- a/README.md +++ b/README.md @@ -257,6 +257,7 @@ See the [docs](docs/README.md) for enabling acceleration and running the unit te In addition to QuEST's [authors](AUTHORS.txt), we sincerely thank the following external contributors to QuEST. +- [James Richings](https://github.com/JPRichings) for patching a v4 overflow bug. - [Luc Jaulmes](https://github.com/lucjaulmes) for patching v4's CMake installation. - [Jakub Adamski](https://github.com/jjacobx) for optimising distributed communication of max-size messages. - [Bruno Villasenor Alvarez](https://github.com/bvillasen) of [AMD](https://www.amd.com/en.html) for porting the v3 GPU backend to [HIP](https://github.com/ROCm-Developer-Tools/HIP), for compatibility with AMD GPUs. diff --git a/quest/src/core/bitwise.hpp b/quest/src/core/bitwise.hpp index 910840478..5479c4ee0 100644 --- a/quest/src/core/bitwise.hpp +++ b/quest/src/core/bitwise.hpp @@ -4,6 +4,7 @@ * * @author Tyson Jones * @author Erich Essmann (improved OS agnosticism) + * @author James Richings (patched setBit) */ #ifndef BITWISE_HPP @@ -106,7 +107,8 @@ INLINE qindex insertBit(qindex number, int bitIndex, int bitValue) { INLINE qindex setBit(qindex number, int bitIndex, int bitValue) { - qindex bitInPlace = bitValue << bitIndex; + // beware that shifting the raw int would overflow (#623) + qindex bitInPlace = ((qindex) bitValue) << bitIndex; qindex oneInPlace = QINDEX_ONE << bitIndex; return (number & ~oneInPlace) | bitInPlace; } From 8db1c06b70b9a8642d8fc14bc09544d3500616d1 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 25 May 2025 21:53:41 +0200 Subject: [PATCH 10/12] separated source (C++17) and testing (C++20) standards This required editing the source to exclude designated initialisers which are not supported in C++17 except through compiler extensions. Such extensions are enabled by default in Clang and GCC but require explicit enabling in e.g. MSVC. We've here made the decision to widen default-compiler support by making struct initialisation a little uglier. --- CMakeLists.txt | 11 +++- quest/include/matrices.h | 60 +++++++++++--------- quest/src/api/channels.cpp | 38 +++++++------ quest/src/api/environment.cpp | 23 +++----- quest/src/api/matrices.cpp | 100 ++++++++++++++++------------------ quest/src/api/paulis.cpp | 41 +++++++------- quest/src/api/qureg.cpp | 67 ++++++++++++----------- quest/src/core/localiser.cpp | 36 +++++++----- quest/src/core/printer.cpp | 34 +++++++----- quest/src/core/utilities.cpp | 69 +++++++++++++---------- tests/CMakeLists.txt | 1 + 11 files changed, 256 insertions(+), 224 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 69acf74ac..1fe522059 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -278,11 +278,18 @@ set_target_properties(QuEST PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR} ) -# Add required C and C++ standards +# Add required C and C++ standards. +# Note the QuEST interface(s) require only C11 and C++14, +# while the source code is entirely C++ and requires C++17, +# and the tests further require C++20 (handled in tests/). +# Yet, we here specify C++17 for the source, and C11 as only +# applies to the C interface when users specify USER_SOURCE, +# to attemptedly minimise user confusion. Users wishing to +# link QuEST with C++14 should separate compilation. target_compile_features(QuEST PUBLIC c_std_11 - cxx_std_20 + cxx_std_17 ) # Turn on all compiler warnings diff --git a/quest/include/matrices.h b/quest/include/matrices.h index 8ff4e9ff3..7fa38ab4f 100644 --- a/quest/include/matrices.h +++ b/quest/include/matrices.h @@ -9,6 +9,10 @@ * definitions, for safety. Some intendedly private functions are necessarily * exposed here to the user, and are prefixed with an underscore. * + * Note too that designated initialisers are generally avoided, since while + * C99/C11 compatible, they are not explicitly supported by C++14 (only from + * C++20) except through compiler extensions + * * @author Tyson Jones * @author Richard Meister (aided in design) * @author Erich Essmann (aided in design, patched on MSVC) @@ -321,13 +325,14 @@ extern void _validateNewElemsPtrNotNull(qcomp* ptr, const char* caller); static inline CompMatr1 getCompMatr1(qcomp** in) { _validateNewNestedElemsPtrNotNull(in, 1, __func__); - CompMatr1 out = { - .numQubits = 1, - .numRows = 2, - .elems = { - {in[0][0], in[0][1]}, - {in[1][0], in[1][1]}} - }; + CompMatr1 out; + + out.numQubits = 1; + out.numRows = 2; + for (int r=0; r<2; r++) + for (int c=0; c<2; c++) + out.elems[r][c] = in[r][c]; + return out; } @@ -346,15 +351,14 @@ static inline CompMatr1 getCompMatr1(qcomp** in) { static inline CompMatr2 getCompMatr2(qcomp** in) { _validateNewNestedElemsPtrNotNull(in, 2, __func__); - CompMatr2 out = { - .numQubits = 2, - .numRows = 4, - .elems = { - {in[0][0], in[0][1], in[0][2], in[0][3]}, - {in[1][0], in[1][1], in[1][2], in[1][3]}, - {in[2][0], in[2][1], in[2][2], in[2][3]}, - {in[3][0], in[3][1], in[3][2], in[3][3]}} - }; + CompMatr2 out; + + out.numQubits = 2; + out.numRows = 4; + for (int r=0; r<4; r++) + for (int c=0; c<4; c++) + out.elems[r][c] = in[r][c]; + return out; } @@ -374,11 +378,13 @@ static inline CompMatr2 getCompMatr2(qcomp** in) { static inline DiagMatr1 getDiagMatr1(qcomp* in) { _validateNewElemsPtrNotNull(in, __func__); - DiagMatr1 out = { - .numQubits = 1, - .numElems = 2, - .elems = {in[0], in[1]} - }; + DiagMatr1 out; + + out.numQubits = 1; + out.numElems = 2; + for (int i=0; i<2; i++) + out.elems[i] = in[i]; + return out; } @@ -397,11 +403,13 @@ static inline DiagMatr1 getDiagMatr1(qcomp* in) { static inline DiagMatr2 getDiagMatr2(qcomp* in) { _validateNewElemsPtrNotNull(in, __func__); - DiagMatr2 out = { - .numQubits = 2, - .numElems = 4, - .elems = {in[0], in[1], in[2], in[3]} - }; + DiagMatr2 out; + + out.numQubits = 2; + out.numElems = 4; + for (int i=0; i<4; i++) + out.elems[i] = in[i]; + return out; } diff --git a/quest/src/api/channels.cpp b/quest/src/api/channels.cpp index e604eba3a..d6e3ac4fb 100644 --- a/quest/src/api/channels.cpp +++ b/quest/src/api/channels.cpp @@ -131,26 +131,30 @@ SuperOp allocSuperOp(int numQubits) { qindex numRows = powerOf2(2 * numQubits); qindex numElems = numRows * numRows; + // attempt top allocate 1D memory qcomp* cpuMem = cpu_allocArray(numElems); // nullptr if failed qcomp* gpuMem = nullptr; if (getQuESTEnv().isGpuAccelerated) gpuMem = gpu_allocArray(numElems); // nullptr if failed - SuperOp out = { - .numQubits = numQubits, - .numRows = numRows, + // prepare output SuperOp (avoiding C++20 designated initialiser) + SuperOp out; + out.numQubits = numQubits; + out.numRows = numRows; - .cpuElems = cpu_allocAndInitMatrixWrapper(cpuMem, numRows), // nullptr if failed - .cpuElemsFlat = cpuMem, - .gpuElemsFlat = gpuMem, + // attemptedly allocate 2D alias for 1D CPU memory + out.cpuElems = cpu_allocAndInitMatrixWrapper(cpuMem, numRows); // nullptr if failed + out.cpuElemsFlat = cpuMem; + out.gpuElemsFlat = gpuMem; - .wasGpuSynced = cpu_allocHeapFlag() // nullptr if failed - }; + // attemptedly allocate (un-initialised) flags in the heap so that struct copies are mutable + out.wasGpuSynced = cpu_allocHeapFlag(); // nullptr if failed // if heap flag allocated, mark it as unsynced (caller will handle if allocation failed) if (mem_isAllocated(out.wasGpuSynced)) *(out.wasGpuSynced) = 0; + // caller will handle if any above allocations failed return out; } @@ -176,16 +180,14 @@ extern "C" KrausMap createKrausMap(int numQubits, int numOperators) { // validation ensures this never overflows qindex numRows = powerOf2(numQubits); - KrausMap out = { - .numQubits = numQubits, - .numMatrices = numOperators, - .numRows = numRows, - - .matrices = cpu_allocMatrixList(numRows, numOperators), // is or contains nullptr if failed - .superop = allocSuperOp(numQubits), // heap fields are or contain nullptr if failed - - .isApproxCPTP = util_allocEpsilonSensitiveHeapFlag(), // nullptr if failed - }; + // attempt to allocate output KrausMap fields (avoiding C++20 designated initialiser) + KrausMap out; + out.numQubits = numQubits, + out.numMatrices = numOperators, + out.numRows = numRows, + out.matrices = cpu_allocMatrixList(numRows, numOperators); // is or contains nullptr if failed + out.superop = allocSuperOp(numQubits); // heap fields are or contain nullptr if failed + out.isApproxCPTP = util_allocEpsilonSensitiveHeapFlag(); // nullptr if failed // free memory before throwing validation error to avoid memory leaks freeAllMemoryIfAnyAllocsFailed(out); // sets out.matrices=nullptr if failed diff --git a/quest/src/api/environment.cpp b/quest/src/api/environment.cpp index 226fe1401..5c29cbcb8 100644 --- a/quest/src/api/environment.cpp +++ b/quest/src/api/environment.cpp @@ -130,21 +130,14 @@ void validateAndInitCustomQuESTEnv(int useDistrib, int useGpuAccel, int useMulti if (globalEnvPtr == nullptr) error_allocOfQuESTEnvFailed(); - /// @todo the below memcpy is naughty (QuESTEnv has no trivial copy-assignment) and causes compiler warning. Fix! - - // initialise it to a local env - QuESTEnv env = { - - // bind deployment info - .isMultithreaded = useMultithread, - .isGpuAccelerated = useGpuAccel, - .isDistributed = useDistrib, - - // set distributed info - .rank = (useDistrib)? comm_getRank() : 0, - .numNodes = (useDistrib)? comm_getNumNodes() : 1, - }; - memcpy(globalEnvPtr, &env, sizeof(QuESTEnv)); + // bind deployment info to global instance + globalEnvPtr->isMultithreaded = useMultithread; + globalEnvPtr->isGpuAccelerated = useGpuAccel; + globalEnvPtr->isDistributed = useDistrib; + + // bind distributed info + globalEnvPtr->rank = (useDistrib)? comm_getRank() : 0; + globalEnvPtr->numNodes = (useDistrib)? comm_getNumNodes() : 1; } diff --git a/quest/src/api/matrices.cpp b/quest/src/api/matrices.cpp index efcef4054..019b70f79 100644 --- a/quest/src/api/matrices.cpp +++ b/quest/src/api/matrices.cpp @@ -216,26 +216,26 @@ extern "C" CompMatr createCompMatr(int numQubits) { qindex numRows = powerOf2(numQubits); qindex numElems = numRows * numRows; + // attempt to allocate 1D memory qcomp* cpuMem = cpu_allocArray(numElems); // nullptr if failed qcomp* gpuMem = nullptr; if (getQuESTEnv().isGpuAccelerated) gpuMem = gpu_allocArray(numElems); // nullptr if failed - // initialise all CompMatr fields inline because most are const - CompMatr out = { - .numQubits = numQubits, - .numRows = numRows, + // prepare output CompMatr (avoiding C++20 designated initialiser) + CompMatr out; + out.numQubits = numQubits; + out.numRows = numRows; - // allocate flags in the heap so that struct copies are mutable - .isApproxUnitary = util_allocEpsilonSensitiveHeapFlag(), // nullptr if failed - .isApproxHermitian = util_allocEpsilonSensitiveHeapFlag(), + // attemptedly allocate (un-initialised) flags in the heap so that struct copies are mutable + out.isApproxUnitary = util_allocEpsilonSensitiveHeapFlag(); // nullptr if failed + out.isApproxHermitian = util_allocEpsilonSensitiveHeapFlag(); + out.wasGpuSynced = cpu_allocHeapFlag(); // nullptr if failed - .wasGpuSynced = cpu_allocHeapFlag(), // nullptr if failed - - .cpuElems = cpu_allocAndInitMatrixWrapper(cpuMem, numRows), // nullptr if failed - .cpuElemsFlat = cpuMem, - .gpuElemsFlat = gpuMem - }; + // attemptedly allocate 2D alias for 1D CPU memory + out.cpuElems = cpu_allocAndInitMatrixWrapper(cpuMem, numRows); // nullptr if failed + out.cpuElemsFlat = cpuMem; + out.gpuElemsFlat = gpuMem; validateMatrixAllocs(out, __func__); setInitialHeapFlags(out); @@ -250,24 +250,21 @@ extern "C" DiagMatr createDiagMatr(int numQubits) { // validation ensures this never overflows qindex numElems = powerOf2(numQubits); - // initialise all CompMatr fields inline because most are const - DiagMatr out = { - .numQubits = numQubits, - .numElems = numElems, - - // allocate flags in the heap so that struct copies are mutable - .isApproxUnitary = util_allocEpsilonSensitiveHeapFlag(), // nullptr if failed - .isApproxHermitian = util_allocEpsilonSensitiveHeapFlag(), - .isApproxNonZero = util_allocEpsilonSensitiveHeapFlag(), - .isStrictlyNonNegative = cpu_allocHeapFlag(), // nullptr if failed - .wasGpuSynced = cpu_allocHeapFlag(), + // prepare output DiagMatr (avoiding C++20 designated initialiser) + DiagMatr out; + out.numQubits = numQubits, + out.numElems = numElems, - // 1D CPU memory - .cpuElems = cpu_allocArray(numElems), // nullptr if failed + // attempt to allocate (uninitialised) flags in the heap so that struct copies are mutable + out.isApproxUnitary = util_allocEpsilonSensitiveHeapFlag(); // nullptr if failed + out.isApproxHermitian = util_allocEpsilonSensitiveHeapFlag(); + out.isApproxNonZero = util_allocEpsilonSensitiveHeapFlag(); + out.isStrictlyNonNegative = cpu_allocHeapFlag(); // nullptr if failed + out.wasGpuSynced = cpu_allocHeapFlag(); - // 1D GPU memory - .gpuElems = (getQuESTEnv().isGpuAccelerated)? gpu_allocArray(numElems) : nullptr // nullptr if failed or not needed - }; + // attempt to allocate 1D memory (nullptr if failed or not allocated) + out.cpuElems = cpu_allocArray(numElems); + out.gpuElems = (getQuESTEnv().isGpuAccelerated)? gpu_allocArray(numElems) : nullptr; validateMatrixAllocs(out, __func__); setInitialHeapFlags(out); @@ -289,30 +286,27 @@ FullStateDiagMatr validateAndCreateCustomFullStateDiagMatr(int numQubits, int us qindex numElems = powerOf2(numQubits); qindex numElemsPerNode = numElems / (useDistrib? env.numNodes : 1); // divides evenly - FullStateDiagMatr out = { - - .numQubits = numQubits, - .numElems = numElems, - - // data deployment configuration; disable distrib if deployed to 1 node - .isGpuAccelerated = useGpuAccel, - .isMultithreaded = useMultithread, - .isDistributed = useDistrib && (env.numNodes > 1), - .numElemsPerNode = numElemsPerNode, - - // allocate flags in the heap so that struct copies are mutable - .isApproxUnitary = util_allocEpsilonSensitiveHeapFlag(), // nullptr if failed - .isApproxHermitian = util_allocEpsilonSensitiveHeapFlag(), - .isApproxNonZero = util_allocEpsilonSensitiveHeapFlag(), - .isStrictlyNonNegative = cpu_allocHeapFlag(), // nullptr if failed - .wasGpuSynced = cpu_allocHeapFlag(), - - // 1D CPU memory - .cpuElems = cpu_allocArray(numElemsPerNode), // nullptr if failed - - // 1D GPU memory - .gpuElems = (useGpuAccel)? gpu_allocArray(numElemsPerNode) : nullptr, // nullptr if failed or not needed - }; + // prepare output FullStateDiagMatr (avoiding C++20 designated initialiser) + FullStateDiagMatr out; + out.numQubits = numQubits; + out.numElems = numElems; + + // bind deployments, disabling distribution if using a single MPI node + out.isGpuAccelerated = useGpuAccel; + out.isMultithreaded = useMultithread; + out.isDistributed = useDistrib && (env.numNodes > 1); + out.numElemsPerNode = numElemsPerNode; + + // allocate (unitialised) flags in the heap so that struct copies are mutable + out.isApproxUnitary = util_allocEpsilonSensitiveHeapFlag(); // nullptr if failed + out.isApproxHermitian = util_allocEpsilonSensitiveHeapFlag(); + out.isApproxNonZero = util_allocEpsilonSensitiveHeapFlag(); + out.isStrictlyNonNegative = cpu_allocHeapFlag(); // nullptr if failed + out.wasGpuSynced = cpu_allocHeapFlag(); + + // allocate 1D memory (nullptr if failed or not allocated) + out.cpuElems = cpu_allocArray(numElemsPerNode); + out.gpuElems = (useGpuAccel)? gpu_allocArray(numElemsPerNode) : nullptr; validateMatrixAllocs(out, __func__); setInitialHeapFlags(out); diff --git a/quest/src/api/paulis.cpp b/quest/src/api/paulis.cpp index bbfa5bfde..2efa22834 100644 --- a/quest/src/api/paulis.cpp +++ b/quest/src/api/paulis.cpp @@ -246,10 +246,11 @@ PauliStr paulis_getShiftedPauliStr(PauliStr str, int pauliShift) { // and add them to highPaulis; we don't have to force lose upper bits of high paulis PAULI_MASK_TYPE upperBits = concatenateBits(str.highPaulis, lostBits, bitShift); - return { - .lowPaulis = lowerBits, - .highPaulis = upperBits - }; + // return a new stack PauliStr instance (avoiding C++20 initialiser) + PauliStr out; + out.lowPaulis = lowerBits; + out.highPaulis = upperBits; + return out; } @@ -257,10 +258,11 @@ PauliStr paulis_getKetAndBraPauliStr(PauliStr str, Qureg qureg) { PauliStr shifted = paulis_getShiftedPauliStr(str, qureg.numQubits); - return { - .lowPaulis = str.lowPaulis | shifted.lowPaulis, - .highPaulis = str.highPaulis | shifted.highPaulis - }; + // return a new stack PauliStr instance (avoiding C++20 initialiser) + PauliStr out; + out.lowPaulis = str.lowPaulis | shifted.lowPaulis; + out.highPaulis = str.highPaulis | shifted.highPaulis; + return out; } @@ -313,11 +315,11 @@ extern "C" PauliStr getPauliStr(const char* paulis, int* indices, int numPaulis) highPaulis |= pauli << (2*(indices[i] - MAX_NUM_PAULIS_PER_MASK)); } - // return a new stack PauliStr instance, returning by copy - return { - .lowPaulis = lowPaulis, - .highPaulis = highPaulis - }; + // return a new stack PauliStr instance (avoiding C++20 initialiser) + PauliStr out; + out.lowPaulis = lowPaulis; + out.highPaulis = highPaulis; + return out; } @@ -388,13 +390,12 @@ extern "C" PauliStrSum createPauliStrSum(PauliStr* strings, qcomp* coeffs, qinde // note we do not require nor impose the strings to be unique validate_newPauliStrSumParams(numTerms, __func__); - // create struct - PauliStrSum out = { - .numTerms = numTerms, - .strings = cpu_allocPauliStrings(numTerms), // nullptr if failed - .coeffs = cpu_allocArray(numTerms), // nullptr if failed - .isApproxHermitian = util_allocEpsilonSensitiveHeapFlag(), // nullptr if failed - }; + // prepare output PauliStrSum (avoiding C++20 designated initialiser) + PauliStrSum out; + out.numTerms = numTerms; + out.strings = cpu_allocPauliStrings(numTerms); // nullptr if failed + out.coeffs = cpu_allocArray(numTerms); // nullptr if failed + out.isApproxHermitian = util_allocEpsilonSensitiveHeapFlag(); // nullptr if failed // if either alloc failed, clear both before validation to avoid leak freeAllMemoryIfAnyAllocsFailed(out); diff --git a/quest/src/api/qureg.cpp b/quest/src/api/qureg.cpp index 626d3220e..98068f079 100644 --- a/quest/src/api/qureg.cpp +++ b/quest/src/api/qureg.cpp @@ -45,38 +45,41 @@ Qureg qureg_populateNonHeapFields(int numQubits, int isDensMatr, int useDistrib, (2*numQubits - logNumNodes) : ( numQubits - logNumNodes); - return { - // bind deployment info - .isMultithreaded = useMultithread, - .isGpuAccelerated = useGpuAccel, - .isDistributed = useDistrib, - - // optionally bind distributed info, noting that in distributed environments, - // the non-distributed quregs are duplicated on each node and each believe - // they are the root node, with no other nodes existing; this is essential so - // that these quregs can agnostically use distributed routines which consult - // the rank, but it will interfere with naive root-only printing logic - .rank = (useDistrib)? env.rank : 0, - .numNodes = (useDistrib)? env.numNodes : 1, - .logNumNodes = (useDistrib)? logBase2(env.numNodes) : 0, // duplicated for clarity - - // set dimensions - .isDensityMatrix = isDensMatr, - .numQubits = numQubits, - .numAmps = (isDensMatr)? powerOf2(2*numQubits) : powerOf2(numQubits), - .logNumAmps = (isDensMatr)? 2*numQubits : numQubits, - - // set dimensions per node (even if not distributed) - .numAmpsPerNode = powerOf2(logNumAmpsPerNode), - .logNumAmpsPerNode = logNumAmpsPerNode, - .logNumColsPerNode = (isDensMatr)? numQubits - logNumNodes : 0, // used only by density matrices - - // caller will allocate heap memory as necessary - .cpuAmps = nullptr, - .gpuAmps = nullptr, - .cpuCommBuffer = nullptr, - .gpuCommBuffer = nullptr - }; + // prepare output Qureg (avoiding C++20 designated initialiser) + Qureg out; + + // bind deployment info + out.isMultithreaded = useMultithread; + out.isGpuAccelerated = useGpuAccel; + out.isDistributed = useDistrib; + + // optionally bind distributed info, noting that in distributed environments, + // the non-distributed quregs are duplicated on each node and each believe + // they are the root node, with no other nodes existing; this is essential so + // that these quregs can agnostically use distributed routines which consult + // the rank, but it will interfere with naive root-only printing logic + out.rank = (useDistrib)? env.rank : 0; + out.numNodes = (useDistrib)? env.numNodes : 1; + out.logNumNodes = (useDistrib)? logBase2(env.numNodes) : 0; // duplicated for clarity + + // bind dimensions + out.isDensityMatrix = isDensMatr; + out.numQubits = numQubits; + out.numAmps = (isDensMatr)? powerOf2(2*numQubits) : powerOf2(numQubits); + out.logNumAmps = (isDensMatr)? 2*numQubits : numQubits; + + // bind dimensions per node (even if not distributed) + out.numAmpsPerNode = powerOf2(logNumAmpsPerNode); + out.logNumAmpsPerNode = logNumAmpsPerNode; + out.logNumColsPerNode = (isDensMatr)? numQubits - logNumNodes : 0; // used only by density matrices + + // caller will allocate heap memory as necessary + out.cpuAmps = nullptr; + out.gpuAmps = nullptr; + out.cpuCommBuffer = nullptr; + out.gpuCommBuffer = nullptr; + + return out; } diff --git a/quest/src/core/localiser.cpp b/quest/src/core/localiser.cpp index 7cc84ba06..9ef6148f1 100644 --- a/quest/src/core/localiser.cpp +++ b/quest/src/core/localiser.cpp @@ -1646,21 +1646,23 @@ void localiser_densmatr_oneQubitDamping(Qureg qureg, int qubit, qreal prob) { CompMatr getSpoofedCompMatrFromSuperOp(SuperOp op) { - CompMatr out = { - // superoperator acts on twice as many qubits - .numQubits = 2 * op.numQubits, - .numRows = op.numRows, - - // heap fields are not consulted - .isApproxUnitary = nullptr, - .isApproxHermitian = nullptr, - .wasGpuSynced = nullptr, - - // copy pointers (noting cpuElems is 2D/nested) - .cpuElems = op.cpuElems, - .cpuElemsFlat = op.cpuElemsFlat, - .gpuElemsFlat = op.gpuElemsFlat - }; + // prepare output CompMatr (avoiding C++20 designated initialiser) + CompMatr out; + + // superoperator acts on twice as many qubits + out.numQubits = 2 * op.numQubits; + out.numRows = op.numRows; + + // heap fields are not consulted + out.isApproxUnitary = nullptr; + out.isApproxHermitian = nullptr; + out.wasGpuSynced = nullptr; + + // copy pointers (noting cpuElems is 2D/nested) + out.cpuElems = op.cpuElems; + out.cpuElemsFlat = op.cpuElemsFlat; + out.gpuElemsFlat = op.gpuElemsFlat; + return out; } @@ -2108,6 +2110,10 @@ qcomp localiser_statevec_calcExpecPauliStrSum(Qureg qureg, PauliStrSum sum) { /// acceptable to grow a list and pass it to a utility function, since we /// always assume the number of terms in the PauliStrSum is tractable! totalValue += coeff * termValue; + + // prefixX wasn't used since it only informs pair-ranks which are not + // consulted here (due to being embarrassingly parallel); we suppress warning + (void) prefixX; } } diff --git a/quest/src/core/printer.cpp b/quest/src/core/printer.cpp index 83452e64a..8a7bea15b 100644 --- a/quest/src/core/printer.cpp +++ b/quest/src/core/printer.cpp @@ -1114,21 +1114,24 @@ void print_elems(KrausMap map, string indent) { if (!comm_isRootNode()) return; - // we ignore the superoperator, and instead print every CPU-only Kraus map in-turn + // we ignore the superoperator, and instead print every CPU-only Kraus map in-turn... for (qindex i=0; i> rows, string indent // find max-width of left column size_t maxWidth = 0; - for (auto const& [key, value] : rows) + for (auto const& [key, value] : rows) { if (key.length() > maxWidth) maxWidth = key.length(); + // pedantically suppressing unused-variable warning + // (while still mirroring below enumeration for clarity) + (void) value; + } + // print table title (indented) cout << indent << getTableTitleStr(title) << endl; diff --git a/quest/src/core/utilities.cpp b/quest/src/core/utilities.cpp index e5b8bd506..b1238f71e 100644 --- a/quest/src/core/utilities.cpp +++ b/quest/src/core/utilities.cpp @@ -894,19 +894,12 @@ util_VectorIndexRange util_getLocalIndRangeOfVectorElemsWithinNode(int rank, qin // global indices of user's targeted elements which are contained within node qindex globalRangeStartInd = std::max(elemStartInd, nodeStartInd); qindex globalRangeEndInd = std::min(elemEndInd, nodeEndInd); - qindex numLocalElems = globalRangeEndInd - globalRangeStartInd; - // local indices of user's targeted elements to overwrite - qindex localRangeStartInd = globalRangeStartInd % numElemsPerNode; - - // local indices of user's passed elements that correspond to above - qindex localOffsetInd = globalRangeStartInd - elemStartInd; - - return { - .localDistribStartInd = localRangeStartInd, - .localDuplicStartInd = localOffsetInd, - .numElems = numLocalElems - }; + util_VectorIndexRange out; + out.numElems = globalRangeEndInd - globalRangeStartInd; // number of local elems in range + out.localDistribStartInd = globalRangeStartInd % numElemsPerNode; // local inds of user's targeted elems to overwrite + out.localDuplicStartInd = globalRangeStartInd - elemStartInd; // local inds of user's passed elems that correspond to above + return out; } @@ -938,46 +931,62 @@ qreal util_getTwoQubitDephasingTerm(qreal prob) { util_Scalars util_getOneQubitDepolarisingFactors(qreal prob) { + util_Scalars out; + // effected where braQubit == ketQubit - qreal facAA = 1 - (2 * prob / 3); - qreal facBB = 2 * prob / 3; + out.c1 = 1 - (2 * prob / 3); // AA + out.c2 = 2 * prob / 3; // BB // effected where braQubit != ketQubit - qreal facAB = 1 - (4 * prob / 3); + out.c3 = 1 - (4 * prob / 3); // AB + + // not used + out.c4 = 0; - return {.c1=facAA, .c2=facBB, .c3=facAB, .c4=0}; // c4 ignored + return out; } util_Scalars util_getTwoQubitDepolarisingFactors(qreal prob) { - return { - .c1 = 1 - (4 * prob / 5), - .c2 = 4 * prob / 15, - .c3 = - (16 * prob / 15), - .c4 = 0 // ignored - }; + util_Scalars out; + + out.c1 = 1 - (4 * prob / 5); + out.c2 = 4 * prob / 15; + out.c3 = - (16 * prob / 15); + + out.c4 = 0; // not used + + return out; } util_Scalars util_getOneQubitPauliChannelFactors(qreal pI, qreal pX, qreal pY, qreal pZ) { + util_Scalars out; + // effected where braQubit == ketQubit - qreal facAA = pI + pZ; - qreal facBB = pX + pY; + out.c1 = pI + pZ; // AA + out.c2 = pX + pY; // BB // effected where braQubit != ketQubit - qreal facAB = pI - pZ; - qreal facBA = pX - pY; + out.c3 = pI - pZ; // AB + out.c4 = pX - pY; // BA - return {.c1=facAA, .c2=facBB, .c3=facAB, .c4=facBA}; + return out; } util_Scalars util_getOneQubitDampingFactors(qreal prob) { + util_Scalars out; + // we assume 0 < prob < 1 (true even of the inverse channel), so c1 is always real - qreal c1 = std::sqrt(1 - prob); - qreal c2 = 1 - prob; + out.c1 = std::sqrt(1 - prob); + out.c2 = 1 - prob; + + // not used + out.c3 = 0; + out.c4 = 0; - return {.c1=c1, .c2=c2, .c3=0, .c4=0}; //c3 and c4 ignored + return out; } qreal util_getMaxProbOfOneQubitDephasing() { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 54c8c396a..ba4fe0d78 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(tests main.cpp ) target_link_libraries(tests PRIVATE QuEST::QuEST Catch2::Catch2) +target_compile_features(tests PUBLIC cxx_std_20) add_subdirectory(unit) add_subdirectory(utils) From 835208e38735ef35341191eceeb4bc14cf81684e Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Tue, 27 May 2025 22:52:18 +0200 Subject: [PATCH 11/12] optimised applyPauliGadget edgecase When the passed PauliStr is identity and no control qubits are imposed, the function merely effects a change in global phase. For density matrices, this induces no change at all; the two constituent operations upon the Choi vector cancel one-another, wasting time and numerical accuracy. So, we abort in that scenario. This is truly an insignificant runtime and accuracy optimisation, and this scenario is superfluously handled mostly to document the validity of the scenario (i.e. the use of gadgets to effect arbitrary phase changes) --- quest/src/api/operations.cpp | 15 ++++++++++----- quest/src/api/paulis.cpp | 8 ++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/quest/src/api/operations.cpp b/quest/src/api/operations.cpp index 01d562542..dbef67707 100644 --- a/quest/src/api/operations.cpp +++ b/quest/src/api/operations.cpp @@ -29,6 +29,7 @@ using std::vector; * PRVIATE UTILITIES */ +extern bool paulis_isIdentity(PauliStr str); extern bool paulis_hasOddNumY(PauliStr str); extern PauliStr paulis_getShiftedPauliStr(PauliStr str, int pauliShift); extern PauliStr paulis_getKetAndBraPauliStr(PauliStr str, Qureg qureg); @@ -1450,11 +1451,15 @@ void applyMultiStateControlledPauliGadget(Qureg qureg, int* controls, int* state validate_controlsAndPauliStrTargets(qureg, controls, numControls, str, __func__); validate_controlStates(states, numControls, __func__); // permits states==nullptr - /// @todo - /// CRUCIAL NOTE: - /// exp(theta I..I) might be algorithmically ok (I'm not sure), but it WILL NOT - /// effect a global phase change of theta (I think). Should validate against this - /// sitaution just in case, or make the doc extremely explicit + // a non-controlled str=I effects a global phase change (of -angle/2) which does not + // at all change a density matrix; the subsequent dagger operation would undo it, + // which we avoid to preserve numerical accuracy + if (paulis_isIdentity(str) && numControls == 0 && qureg.isDensityMatrix) + return; + + // when numControls >= 1, all amps satisfying the control condition undergo a phase + // change of -angle/2, as if all non-control-qubits were targeted by exp(-angle/2)I, + // which is sufficiently efficient using the existing gadget backend function qreal phase = util_getPhaseFromGateAngle(angle); auto ctrlVec = util_getVector(controls, numControls); diff --git a/quest/src/api/paulis.cpp b/quest/src/api/paulis.cpp index 2efa22834..ad5d5c641 100644 --- a/quest/src/api/paulis.cpp +++ b/quest/src/api/paulis.cpp @@ -95,6 +95,14 @@ void freeAllMemoryIfAnyAllocsFailed(PauliStrSum sum) { */ +bool paulis_isIdentity(PauliStr str) { + + return + (str.lowPaulis == 0) && + (str.highPaulis == 0); +} + + int paulis_getPauliAt(PauliStr str, int ind) { return (ind < MAX_NUM_PAULIS_PER_MASK)? From e9fa519617edd498a9f7e8901ce7273f44ceebe1 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Tue, 27 May 2025 23:43:31 +0200 Subject: [PATCH 12/12] extended CI example testing Now, all standalone C and C++ files in the 'isolated' and 'automated' subdirectories of 'examples' will be executed by the compiler Github Action. The former is to just catch/log interface issues not reflected by the unit tests, while the latter empowers external contributors to include casual test code with their PRs which will be run cross-platform, cross-compiler and cross-precision. This is a much easier alternative to users attempting to include unit tests in their PRs, and has been setup in preparation for unitaryHACK 2025. Also documented each examples subdir --- .github/workflows/compile.yml | 71 ++++++++++++++----- examples/CMakeLists.txt | 1 + examples/README.md | 4 +- examples/automated/CMakeLists.txt | 3 + examples/automated/README.md | 25 +++++++ examples/automated/report_quest_env.c | 14 ++++ examples/extended/README.md | 11 +++ examples/extended/dynamics.c | 9 +++ examples/extended/dynamics.cpp | 9 +++ examples/isolated/README.md | 12 ++++ .../isolated/initialising_superoperators.c | 1 + examples/tutorials/README.md | 11 +++ 12 files changed, 151 insertions(+), 20 deletions(-) create mode 100644 examples/automated/CMakeLists.txt create mode 100644 examples/automated/README.md create mode 100644 examples/automated/report_quest_env.c create mode 100644 examples/extended/README.md create mode 100644 examples/isolated/README.md create mode 100644 examples/tutorials/README.md diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 8cc4d0eec..64d59a59d 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -2,16 +2,21 @@ # code with (attemptedly) all possible configurations # of operating system, precision, multithreading, # distribution, GPU-acceleration (via CUDA or HIP), -# and cuQuantum (else custom kernels). Currently, -# this wastefully downlaods and installs all needed -# compilers (like libomp, CUDA, ROCm). Compilation +# and cuQuantum (else custom kernels). Compilation # includes the v4 unit and integration tests, the # deprecated v3 tests (when possible), and all the -# example programs. One example executable is then -# run (both C and C++ versions) to ensure the build -# was successful and does not cause link-time errors. -# Note that ARM compilation is not yet tested here, -# but in fact Linux ARM is used by a paid test runner. +# example programs. All 'isolated' example executables +# are then run (both C and C++ versions) to ensure the +# build was successful and does not cause link-time +# errors. Then, all 'automated' examples are run which +# permits contributors to demo or test their changes +# across all operation systems and compilers. +# +# Note: +# - This workflow currently wastefully re-downloads and +# installs all needed compilers (like libomp, CUDA, ROCm) +# - ARM compilation is not tested here, though it is used +# by the paid multithreaded CI tests. # # @author Tyson Jones @@ -142,12 +147,12 @@ jobs: # constants env: - build_dir: "build" cuda_arch: 70 hip_arch: gfx801 rocm_path: /opt/rocm/bin - example_dir: build/examples/isolated - example_fn_pref: reporting_quregs + build_dir: build + isolated_dir: build/examples/isolated + automated_dir: build/examples/automated # perform the job steps: @@ -237,15 +242,43 @@ jobs: - name: Compile run: cmake --build ${{ env.build_dir }} --config Release --parallel - # attempt to run the compiled executable, testing for link-time errors, - # logging stdout and stderr to file (to verify the executable actually ran) - - name: Run (Windows) + # run all compiled isolated examples to test for link-time errors, + # continuing if any fail (since some deliberately fail) + - name: Run isolated examples (Windows) if: ${{ matrix.os == 'windows-latest' }} + working-directory: ${{ env.isolated_dir }}/Release/ + shell: pwsh + run: | + Get-ChildItem -Filter '*.exe' -File | + ForEach-Object { + Write-Host "`r`n[[[ $($_.Name) ]]]`r`n" + & $_.FullName + } + - name: Run isolated examples (Unix) + if: ${{ matrix.os != 'windows-latest' }} + working-directory: ${{ env.isolated_dir }} + run: | + for fn in *_c *_cpp; do + printf "\n[[[ $fn ]]]\n" + ./$fn || true + done + + # run all compiled 'automated' examples + - name: Run automated examples (Windows) + if: ${{ matrix.os == 'windows-latest' }} + working-directory: ${{ env.automated_dir }}/Release/ + shell: pwsh run: | - ./${{ env.example_dir }}/Release/${{ env.example_fn_pref }}_c.exe - ./${{ env.example_dir }}/Release/${{ env.example_fn_pref }}_cpp.exe - - name: Run (non-Windows) + Get-ChildItem -Filter '*.exe' -File | + ForEach-Object { + Write-Host "`r`n[[[ $($_.Name) ]]]`r`n" + & $_.FullName + } + - name: Run automated examples (Unix) if: ${{ matrix.os != 'windows-latest' }} + working-directory: ${{ env.automated_dir }} run: | - ./${{ env.example_dir }}/${{ env.example_fn_pref }}_c - ./${{ env.example_dir }}/${{ env.example_fn_pref }}_cpp + for fn in *_c *_cpp; do + printf "\n[[[ $fn ]]]\n" + ./$fn || true + done diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 2498c710c..00d4c3439 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -59,3 +59,4 @@ endfunction() add_subdirectory(isolated) add_subdirectory(extended) +add_subdirectory(automated) diff --git a/examples/README.md b/examples/README.md index 7fe49d61c..f81a4db64 100644 --- a/examples/README.md +++ b/examples/README.md @@ -7,6 +7,8 @@ @author Tyson Jones --> -The above 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. +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. + +A description of each folder is given within. \ No newline at end of file diff --git a/examples/automated/CMakeLists.txt b/examples/automated/CMakeLists.txt new file mode 100644 index 000000000..5880c2ac0 --- /dev/null +++ b/examples/automated/CMakeLists.txt @@ -0,0 +1,3 @@ +# @author Tyson Jones + +add_all_local_examples() diff --git a/examples/automated/README.md b/examples/automated/README.md new file mode 100644 index 000000000..fb2baa6ae --- /dev/null +++ b/examples/automated/README.md @@ -0,0 +1,25 @@ +# 🔖🤖  Automated examples + + + +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). +Contributors can include rudimentary testing or demo code in this folder (as standalone `.c` or `.cpp` files) +in their pull requests and preview its output on Github, where it is run with every combination of operating system, compiler and precision. +This is intended for debugging and/or logging purposes, rather than for presenting example codes for users. + +> [!IMPORTANT] +> 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. + +The output can be viewed at the `compile.yml` +[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. + +> [!IMPORTANT] +> 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. + +> [!TIP] +> 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. diff --git a/examples/automated/report_quest_env.c b/examples/automated/report_quest_env.c new file mode 100644 index 000000000..7d8cefadc --- /dev/null +++ b/examples/automated/report_quest_env.c @@ -0,0 +1,14 @@ +/** @file + * Shows the output of reportQuESTEnv() on + * Github Action runners + * + * @author Tyson Jones +*/ + +#include "quest.h" + +int main() { + initQuESTEnv(); + reportQuESTEnv(); + finalizeQuESTEnv(); +} diff --git a/examples/extended/README.md b/examples/extended/README.md new file mode 100644 index 000000000..551ca8dde --- /dev/null +++ b/examples/extended/README.md @@ -0,0 +1,11 @@ +# 🔖📚  Extended examples + + + +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. + diff --git a/examples/extended/dynamics.c b/examples/extended/dynamics.c index dd5ae00a7..8b94e0a7d 100644 --- a/examples/extended/dynamics.c +++ b/examples/extended/dynamics.c @@ -1,3 +1,12 @@ +/** @file + * An example of using QuEST (primarily function + * applyTrotterizedPauliStrSumGadget()) to perform + * dynamical simulation via Trotterisation of the + * unitary-time evolution operator. + * + * @author Tyson Jones +*/ + #include "quest.h" #include #include diff --git a/examples/extended/dynamics.cpp b/examples/extended/dynamics.cpp index ccea66f31..ae232e348 100644 --- a/examples/extended/dynamics.cpp +++ b/examples/extended/dynamics.cpp @@ -1,3 +1,12 @@ +/** @file + * An example of using QuEST (primarily function + * applyTrotterizedPauliStrSumGadget()) to perform + * dynamical simulation via Trotterisation of the + * unitary-time evolution operator. + * + * @author Tyson Jones +*/ + #include "quest.h" #include #include diff --git a/examples/isolated/README.md b/examples/isolated/README.md new file mode 100644 index 000000000..5f28a8838 --- /dev/null +++ b/examples/isolated/README.md @@ -0,0 +1,12 @@ +# 🔖🔍  Isolated examples + + + +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. + +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. diff --git a/examples/isolated/initialising_superoperators.c b/examples/isolated/initialising_superoperators.c index e2d6ca96d..5dbc6098b 100644 --- a/examples/isolated/initialising_superoperators.c +++ b/examples/isolated/initialising_superoperators.c @@ -104,6 +104,7 @@ void demo_setSuperOp() { destroySuperOp(c); // array of pointers + n = 2; qcomp* ptrArr[1 << (2*2)]; d = 1 << (2*2); for (int i=0; i + +This folder contains _tutorials_ which walk through the use of QuEST. +