From f07c393d193802f08b28bffa8fa74622cf0100dd Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 01:55:31 +0200 Subject: [PATCH 01/24] added cute emojis to docs --- docs/README.md | 1 + docs/architecture.md | 2 +- docs/cmake.md | 2 +- docs/compile.md | 2 +- docs/compilers.md | 2 +- docs/styleguide.md | 2 ++ docs/v4.md | 2 +- examples/README.md | 4 ++-- 8 files changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/README.md b/docs/README.md index 4b7c7da00..cb4cd666b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -7,6 +7,7 @@ The gpu_launch.sh wrapper script is required to set the correct binding of GPU t ``` #!/bin/bash +# 📖  Documentation # Compute the raw process ID for binding to GPU and NIC lrank=$((SLURM_PROCID % SLURM_NTASKS_PER_NODE)) diff --git a/docs/architecture.md b/docs/architecture.md index 6358a4616..f143c3833 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -4,7 +4,7 @@ @author Tyson Jones --> -# Architecture +# 🏗️  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. diff --git a/docs/cmake.md b/docs/cmake.md index bc3d539c9..c020df0b7 100644 --- a/docs/cmake.md +++ b/docs/cmake.md @@ -6,7 +6,7 @@ --> -# CMake Configuration Options in QuEST +# ⚙️  CMake Version 4 of QuEST includes reworked CMake to support library builds, CMake export, and installation. Here we detail useful variables to configure the compilation of QuEST. If using a Unix-like operating system any of these variables can be set using the `-D` flag when invoking CMake, for example: diff --git a/docs/compile.md b/docs/compile.md index 9921986ab..4f5b545a2 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -11,7 +11,7 @@ use-cases before progressively more visually complicated examples --> -# Compile +# 🛠️  Compile QuEST can be compiled with [CMake](https://cmake.org/) to make a standalone executable, or an exported library, or a library installed on the system. Compiling is configured with variables supplied by the [`-D` flag](https://cmake.org/cmake/help/latest/command/add_definitions.html) to the [CMake CLI](https://cmake.org/cmake/help/latest/guide/user-interaction/index.html#command-line-cmake-tool). This page details _how_ to compile QuEST for varying purposes and hardwares. diff --git a/docs/compilers.md b/docs/compilers.md index f18bc83e2..2a71d4167 100644 --- a/docs/compilers.md +++ b/docs/compilers.md @@ -5,7 +5,7 @@ @author Tyson Jones --> -# Compilers +# 🔧  Compilers QuEST separates compilation of the **_frontend_**, **_backend_** and the **_tests_**, which have progressively stricter compiler requirements. This page details the specialised compilers necessary to enable specific features hardware accelerators, and lists such compilers which are diff --git a/docs/styleguide.md b/docs/styleguide.md index 6e8f435ba..0b94e05bf 100644 --- a/docs/styleguide.md +++ b/docs/styleguide.md @@ -4,6 +4,8 @@ @author Tyson Jones --> +# 🎨  Style guide + Don't agonise about style - write your code as you see fit and we can address major issues in review/PR. Some encouraged convetions include: diff --git a/docs/v4.md b/docs/v4.md index 77df7ea62..1519668a6 100644 --- a/docs/v4.md +++ b/docs/v4.md @@ -1,5 +1,5 @@ -# What's new in v4 +# 🎉  What's new in v4 QuEST `v4` has completely overhauled the API, software architecture, algorithms, implementations and testing. This page details the new features, divided into those relevant to _users_, _developers_ who integrate QuEST into larger software stacks, and _contributors_ who develop QuEST or otherwise peep at the source code! diff --git a/examples/README.md b/examples/README.md index a70a78864..624559a43 100644 --- a/examples/README.md +++ b/examples/README.md @@ -4,12 +4,12 @@ @author Tyson Jones --> -# Examples +# 🔖  Examples 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 [`run.md`](/docs/run.md#tests) respectively. -# Tutorial +# 🎓  Tutorial QuEST is included into a `C` or `C++` project via ```C++ From cbf9ffcb74914f3da732e5af3fb519f93ae045a7 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 01:55:51 +0200 Subject: [PATCH 02/24] added tests README --- tests/README.md | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 tests/README.md diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 000000000..7525aff44 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,47 @@ + + +# 🧪  Tests + +This folder contains QuEST's extensive tests. See [`compile.md`](/docs/compile.md#tests) and [`launch.md`](/docs/launch.md#tests) to get them running. + +The subdirectories are: +- [`utils`](utils/) containing test utilities, including non-optimised functions against which QuEST output is compared. +- [`unit`](unit) containing [unit tests](https://en.wikipedia.org/wiki/Unit_testing) which test individual QuEST functions in isolation, under their entire input domains (where feasible). +- [`integration`](integration/) containing [integration tests](https://en.wikipedia.org/wiki/Integration_testing) which test multiple QuEST functions working at scale. +- [`deprecated`](deprecated/) containing `v3`'s tests and utilities, only used when explicitly [activated](/docs/compile.md#v3). + +The tests use [Catch2](https://github.com/catchorg/Catch2) and are generally structured as +```C++ +TEST_CASE( "someApiFunc", "[funcs]" ) { + + PREPARE_TEST(...) + + SECTION( "correctness" ) { + + SECTION( "statevector" ) { + + auto a = getApiResult(); + auto b = getReferenceResult(); + REQUIRE_AGREE(a, b); + } + + SECTION( "density matrix" ) { + + auto a = getApiResult(); + auto b = getReferenceResult();s + } + } + + SECTION( "validation" ) { + + SECTION( "some way to mess it up" ) { + + REQUIRE_THROWS( someApiFunc(badArgs) ); + } + } +} +``` From 57dd4a26f4ff4bff406fd85279d54fb63fdb90a2 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 01:56:34 +0200 Subject: [PATCH 03/24] renamed run.md to launch.md --- README.md | 2 +- docs/compile.md | 22 +++++++++++----------- docs/{run.md => launch.md} | 16 ++++++++++++++-- examples/README.md | 2 +- 4 files changed, 27 insertions(+), 15 deletions(-) rename docs/{run.md => launch.md} (96%) diff --git a/README.md b/README.md index baaf64bbf..5fbd5d5a7 100644 --- a/README.md +++ b/README.md @@ -190,7 +190,7 @@ Visit the [docs](docs/) to: - [see what's new in v4](docs/v4.md) - [compile with cmake](docs/compile.md) - [find compatible compilers](docs/compilers.md) - - [launch your simulations](docs/run.md) + - [launch your simulations](docs/launch.md) - [view some examples](examples/) The [API](https://quest-kit.github.io/QuEST/group__api.html) documentation is divided into the following groups: diff --git a/docs/compile.md b/docs/compile.md index 4f5b545a2..46652e44d 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -40,7 +40,7 @@ Compiling is configured with variables supplied by the [`-D` flag](https://cmake > - [`cmake.md`](cmake.md) for the full list of passable compiler variables. > - [`compilers.md`](compilers.md) for a list of compatible and necessary compilers. > - [`qtechtheory.org`](https://quest.qtechtheory.org/download/) for help downloading the necessary compilers. -> - [`run.md`](run.md) for a guide to executing the compiled application. +> - [`launch.md`](launch.md) for a guide to executing the compiled application. > [!TIP] > QuEST's [Github Actions](https://github.com/QuEST-Kit/QuEST/actions/workflows/compile.yml) regularly test QuEST compilation using a broad combination of deployment settings; presently `108` combinations! The [`compile.yml`](/.github/workflows/compile.yml) workflow can serve as a concrete example of how to compile QuEST in a sanitised, virtual setting. @@ -303,7 +303,7 @@ The executables will be saved in the (current) `build` directory, in a sub-direc ```bash ./examples/matrices/cpp_initialisation ``` -as elaborated upon in [`run.md`](run.md#tests). +as elaborated upon in [`launch.md`](launch.md#tests). ------------------ @@ -321,7 +321,7 @@ cmake .. -D ENABLE_TESTING=ON # build cmake --build . ``` -This will compile an executable `tests` in subdirectory `build/tests/`, which can be run as explained in [`run.md`](run.md#tests). +This will compile an executable `tests` in subdirectory `build/tests/`, which can be run as explained in [`launch.md`](launch.md#tests). ### v3 @@ -333,7 +333,7 @@ cmake .. -D ENABLE_TESTING=ON -D ENABLE_DEPRECATED_API=ON # build cmake --build . ``` -and run as explained in [`run.md`](run.md#v3). +and run as explained in [`launch.md`](launch.md#v3). @@ -365,7 +365,7 @@ cmake --build . ``` This is in fact the default behaviour! -The number of threads over which to parallelise QuEST's execution is chosen through setting environment variables, like [`OMP_NUM_THREADS`](https://www.openmp.org/spec-html/5.0/openmpse50.html), immediately before execution. See [`run.md`](run.md#multithreading) for a general guide on multithreaded deployment. +The number of threads over which to parallelise QuEST's execution is chosen through setting environment variables, like [`OMP_NUM_THREADS`](https://www.openmp.org/spec-html/5.0/openmpse50.html), immediately before execution. See [`launch.md`](launch.md#multithreading) for a general guide on multithreaded deployment. @@ -405,7 +405,7 @@ cmake .. -D ENABLE_CUDA=ON -D CMAKE_CUDA_ARCHITECTURES=80 ``` > [!CAUTION] -> Setting the wrong compute capability will cause silently erroneous results. Always run the [unit tests](run.md#tests) after compiling for the first time to confirm it was set correctly. +> Setting the wrong compute capability will cause silently erroneous results. Always run the [unit tests](launch.md#tests) after compiling for the first time to confirm it was set correctly. Building then proceeds as normal, e.g. ```bash @@ -413,7 +413,7 @@ Building then proceeds as normal, e.g. cmake --build . --parallel ``` -See [`run.md`](run.md#gpu-acceleration) for information on +See [`launch.md`](launch.md#gpu-acceleration) for information on ### AMD @@ -440,7 +440,7 @@ cmake .. -D ENABLE_HIP=ON -D CMAKE_HIP_ARCHITECTURES=gfx90a ``` > [!CAUTION] -> Setting the wrong LLVM target name can cause silently erroneous results. Always run the [unit tests](run.md#tests) after compiling for the first time to confirm it was set correctly. +> Setting the wrong LLVM target name can cause silently erroneous results. Always run the [unit tests](launch.md#tests) after compiling for the first time to confirm it was set correctly. Building then proceeds as normal, e.g. @@ -449,7 +449,7 @@ Building then proceeds as normal, e.g. cmake --build . --parallel ``` -The compiled executable can be run like any other, though the GPU behaviour can be prior configured with environment variables. See [`run.md`](run.md#gpu-acceleration) for a general guide on GPU-accelerated deployment. +The compiled executable can be run like any other, though the GPU behaviour can be prior configured with environment variables. See [`launch.md`](launch.md#gpu-acceleration) for a general guide on GPU-accelerated deployment. @@ -483,7 +483,7 @@ cmake .. -D ENABLE_CUDA=ON -D CMAKE_CUDA_ARCHITECTURES=80 -D ENABLE_CUQUANTUM=ON cmake --build . --parallel ``` -No other changes are necessary, nor does cuQuantum affect [hybridising](#multi-gpu) GPU acceleration and distribution. Launching the executable is the same as in the above section. See [`run.md`](run.md#gpu-acceleration). +No other changes are necessary, nor does cuQuantum affect [hybridising](#multi-gpu) GPU acceleration and distribution. Launching the executable is the same as in the above section. See [`launch.md`](launch.md#gpu-acceleration). @@ -511,7 +511,7 @@ cmake .. -D ENABLE_DISTRIBUTION=ON cmake --build . --parallel ``` -Note that distributed executables are launched in a distinct way to the other deployment mods, as explained in [`run.md`](run.md#distribution), +Note that distributed executables are launched in a distinct way to the other deployment mods, as explained in [`launch.md`](launch.md#distribution), diff --git a/docs/run.md b/docs/launch.md similarity index 96% rename from docs/run.md rename to docs/launch.md index 9b1fd2239..c4432974d 100644 --- a/docs/run.md +++ b/docs/launch.md @@ -4,9 +4,9 @@ @author Tyson Jones --> -# Run +# 🚀  Launching -Running your [compiled](compile.md) QuEST application can be as straightforward as running any other executable, though some additional steps are needed to make use of hardware acceleration. This page how to launch your own QuEST applications on different platforms, how to run the examples and unit tests, how to make use of multithreading, GPU-acceleration, distribution and supercomputer job schedulers, and monitor the hardware utilisation. +Launching your [compiled](compile.md) QuEST application can be as straightforward as running any other executable, though some additional steps are needed to make use of hardware acceleration. This page how to launch your own QuEST applications on different platforms, how to run the examples and unit tests, how to make use of multithreading, GPU-acceleration, distribution and supercomputer job schedulers, and monitor the hardware utilisation. **TOC**: - [Examples](#examples) @@ -445,6 +445,18 @@ It is ergo always prudent to explicitly call [`syncQuESTEnv()`](https://quest-ki > - detail controlling local vs distributed gpus with device visibility + +> helpful ARCHER2 snippet: +> ```bash +> # Compute the raw process ID for binding to GPU and NIC +> lrank=$((SLURM_PROCID % SLURM_NTASKS_PER_NODE)) +> +> # Bind the process to the correct GPU and NIC +> export CUDA_VISIBLE_DEVICES=${lrank} +> export UCX_NET_DEVICES=mlx5_${lrank}:1 +> ``` + + --------------------- ## Supercomputers diff --git a/examples/README.md b/examples/README.md index 624559a43..a94ba9f81 100644 --- a/examples/README.md +++ b/examples/README.md @@ -6,7 +6,7 @@ # 🔖  Examples -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 [`run.md`](/docs/run.md#tests) respectively. +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. # 🎓  Tutorial From 737899d7edd624976f53e64b1080bff803fc7a50 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 01:56:46 +0200 Subject: [PATCH 04/24] updated docs README --- docs/README.md | 56 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/docs/README.md b/docs/README.md index cb4cd666b..2f9b7fc12 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,18 +1,52 @@ -> TODO + -gpu_launch.sh wrapper script -The gpu_launch.sh wrapper script is required to set the correct binding of GPU to MPI processes and the correct binding of interconnect interfaces to MPI process and GPU. We provide this centrally for convenience but its contents are simple: -``` -#!/bin/bash # 📖  Documentation -# Compute the raw process ID for binding to GPU and NIC -lrank=$((SLURM_PROCID % SLURM_NTASKS_PER_NODE)) + +> [!IMPORTANT] +> QuEST's `v4` documentation is still under construction. + +QuEST has been overhauled! See + +- 🎉  [`v4.md`](v4.md) for the exciting new features. + +To get started with QuEST, check out + +- 🔧  [`compilers.md`](compilers.md) for a list of compatible compilers. +- 🔗  [`qtechtheory.org`](https://quest.qtechtheory.org/download/) for some help downloading compilers. +- 🛠️  [`compile.md`](compile.md) for instructions on compiling. +- ⚙️  [`cmake.md`](cmake.md) for a list of compiler variables. +- 🚀  [`launch.md`](launch.md) to learn how to run QuEST on laptops to supercomputers. +- 🎓  [`tutorial.md`](/examples/README.md#tutorial) for an introductory tutorial. +- 📋  [API](https://quest-kit.github.io/QuEST/group__api.html) for the documentation of each function. -# Bind the process to the correct GPU and NIC -export CUDA_VISIBLE_DEVICES=${lrank} -export UCX_NET_DEVICES=mlx5_${lrank}:1 +Interested in contributing? Then check out: + +- ❤️  [`contributing.md`](contributing.md) to learn how to make a pull request. +- 🏗️  [`architecture.md`](architecture.md) to understand the code structure. +- 🎨  [`styleguide.md`](styleguide.md) for some tips on writing neat code. + +Want to learn how what's under the hood? Read the +- 🏆  [whitepaper](https://www.nature.com/articles/s41598-019-47174-9) which featured in Scientific Report's [Top 100 in Physics](https://www.nature.com/collections/ecehgdfcba/) +- 📝  [preprint](https://arxiv.org/abs/2311.01512) which derives `v4`'s optimised algorithms. +- 📈  [benchmarks](https://www.youtube.com/watch?v=dQw4w9WgXcQ) which are coming soon! + + +If QuEST is useful to you, feel free to cite +``` +@article{jones2019quest, + title={QuEST and high performance simulation of quantum computers}, + author={Jones, Tyson and Brown, Anna and Bush, Ian and Benjamin, Simon C}, + journal={Scientific reports}, + volume={9}, + number={1}, + pages={10736}, + year={2019}, + publisher={Nature Publishing Group UK London} +} ``` \ No newline at end of file From 57c6ce0cc29d99d16aa4ca97ddd1e75d8793d4de Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 01:57:04 +0200 Subject: [PATCH 05/24] added WIP contributors guide in preparation for unitaryHACK --- docs/contributing.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 docs/contributing.md diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 000000000..e627b08ee --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,15 @@ + + +# ❤️  Contributing + +> [!IMPORTANT] +> This page is under construction! + + +> TODO! + +In the meantime, feel free to open an issue, a discussion or a pull request, or reach out to `tyson.jones.input@gmail.com`. From 1c2345890888503adf9e30a206e27d50d5c0fc64 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 01:59:45 +0200 Subject: [PATCH 06/24] revised doc links --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5fbd5d5a7..022e0e7c3 100644 --- a/README.md +++ b/README.md @@ -186,7 +186,7 @@ QuEST supports: > [!IMPORTANT] > QuEST v4's documentation is still under construction! -Visit the [docs](docs/) to: +Visit the [docs](docs/README.md) to: - [see what's new in v4](docs/v4.md) - [compile with cmake](docs/compile.md) - [find compatible compilers](docs/compilers.md) @@ -270,7 +270,7 @@ then run it with ./min_example ``` -See the [docs](docs/) for enabling acceleration and running the unit tests. +See the [docs](docs/README.md) for enabling acceleration and running the unit tests. --------------------------------- From 58e2cf91ad1653731f3f2337dcc864e8d943686b Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 02:01:25 +0200 Subject: [PATCH 07/24] correct embarrassing typo --- docs/styleguide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/styleguide.md b/docs/styleguide.md index 0b94e05bf..39cf54cd9 100644 --- a/docs/styleguide.md +++ b/docs/styleguide.md @@ -8,7 +8,7 @@ Don't agonise about style - write your code as you see fit and we can address major issues in review/PR. -Some encouraged convetions include: +Some encouraged conventions include: - use `camelCase` for everything except: - constants which use `CAPITALS_AND_UNDERSCORES` From c4738c2127a6ceef53c5d7fafb368ffc3aaa8d95 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 17:20:54 +0200 Subject: [PATCH 08/24] completed tutorial --- examples/README.md | 392 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 390 insertions(+), 2 deletions(-) diff --git a/examples/README.md b/examples/README.md index a94ba9f81..4a2fd619a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -22,7 +22,7 @@ QuEST is included into a `C` or `C++` project via > #define ENABLE_DEPRECATED_API 1 > #include "quest.h" > ``` -> We recommend migrating to the latest `v4` API however, demonstrated below. +> We recommend migrating to the latest `v4` API however as will be showcased below. Simulation typically proceeds as: 1. [Initialise](https://quest-kit.github.io/QuEST/group__environment.html#gab89cfc1bf94265f4503d504b02cf54d4) the QuEST [environment](https://quest-kit.github.io/QuEST/group__environment.html), preparing available GPUs and networks. @@ -38,6 +38,25 @@ Simulation typically proceeds as: Of course, the procedure is limited only by the programmers imagination `¯\_(ツ)_/¯` Let's see an example of these steps below. +> **TOC**: +> - [1. Initialise the environment](#1-initialise-the-environment) +> - [2. Configure the environment](#2-configure-the-environment) +> - [3. Create a `Qureg`](#3-create-a--qureg-) +> - [4. Prepare an initial state](#4-prepare-an-initial-state) +> - [5. Apply operators](#5-apply-operators) +> * [controls](#controls) +> * [paulis](#paulis) +> * [matrices](#matrices) +> * [circuits](#circuits) +> * [measurements](#measurements) +> * [decoherence](#decoherence) +> - [6. Perform calculations](#6-perform-calculations) +> - [7. Report the results](#7-report-the-results) +> - [8. Cleanup](#8-cleanup) +> - [9. Finalise QuEST](#9-finalise-quest) + + + ## 1. Initialise the environment Before calling any other QuEST functions, we must [_initialise_](https://quest-kit.github.io/QuEST/group__environment.html#gab89cfc1bf94265f4503d504b02cf54d4) the QuEST [_environment_](https://quest-kit.github.io/QuEST/group__environment.html). @@ -366,4 +385,373 @@ Qureg (5 qubit density matrix, 32x32 qcomps, 16.1 KiB): ## 5. Apply operators -> TODO \ No newline at end of file +QuEST supports an extensive set of [operators](https://quest-kit.github.io/QuEST/group__operations.html) to effect upon a `Qureg`. +```C++ +int target = 2; +applyHadamard(qureg, target); + +qreal angle = 3.14 / 5; +int targets[] = {4,5,6}; +applyPhaseGadget(qureg, targets, 3, angle); +``` + +> [!IMPORTANT] +> Notice the type of `angle` is [`qreal`](https://quest-kit.github.io/QuEST/group__types.html#ga2d479c159621c76ca6f96abe66f2e69e) rather than the expected `double`. This is a precision agnostic alias for a floating-point, real scalar which allows you to recompile QuEST with a varying [precision](/docs/compile.md#precision) with no modifications to your code. + +### controls + +All unitary operations accept any number of control qubits +```C++ +int controls[] = {0,1,2,3,7,8,9}; +applyMultiControlledSqrtSwap(qureg, controls, 7, targets[0], targets[1]); +``` +and even _control states_ which specify the bits (`0` or `1`) that the respective controls must be in to effect the non-identity operation. +```C++ +int states[] = {0,0,0,1,1,1,0}; +applyMultiStateControlledRotateX(qureg, controls, states, 7, target, angle); +``` + +> [!TIP] +> `C` users can pass inline list arguments using [compound literals](https://en.cppreference.com/w/c/language/compound_literal) +> ```C +> applyMultiControlledMultiQubitNot(qureg, (int[]) {0,1,2}, 3, (int[]) {4,5}, 2); +> ``` +> while `C++` users can pass [vector](https://en.cppreference.com/w/cpp/container/vector) literals or [initializer lists](https://en.cppreference.com/w/cpp/utility/initializer_list), alleviating the need to specify the list lengths. +> ```C++ +> applyMultiControlledMultiQubitNot(qureg, {0,1,2}, {4,5}); +> ``` + +### paulis + +Some operators accept [`PauliStr`](https://quest-kit.github.io/QuEST/structPauliStr.html) which can be [constructed](https://quest-kit.github.io/QuEST/group__paulis__create.html) all sorts of ways - even inline! +```C++ +applyPauliGadget(qureg, getPauliStr("XYZ"), angle); +``` + +> [!TIP] +> Using _one_ QuEST function is _always_ faster than using an equivalent sequence. So +> ```C++ +> applyPauliStr(qureg, getPauliStr("YYYYYYY")); +> ``` +> is _much_ faster than +> ```C++ +> for (int i=0; i<7; i++) +> applyPauliY(qureg, i); +> ``` + +### matrices + +#### `CompMatr1` + +Don't see your operation in the API? You can specify it as a general [matrix](https://quest-kit.github.io/QuEST/group__matrices.html). +```C++ +qcomp x = 1i/sqrt(2); +CompMatr1 matrix = getInlineCompMatr({{-x,x},{-x,-x}}); +applyCompMatr1(qureg, target, matrix); +``` + +> [!IMPORTANT] +> The type [`qcomp`](https://quest-kit.github.io/QuEST/group__types.html#ga4971f489e74bb185b9b2672c14301983) above is a precision agnostic complex scalar, and has beautiful arithmetic overloads! +> ```C++ +> qcomp x = 1.5 + 3.14i; +> qcomp *= 1E3i - 1E-5i; +> ``` +> Beware that in `C++`, `1i` is a _double precision_ literal, so `C++` users should instead +> use the custom precision-agnostic literal `1_i`. +> ```C++ +> qcomp x = 1.5 + 3.14_i; +> ``` + +#### `CompMatr` + +Want a bigger matrix? No problem - they can be [any size](https://quest-kit.github.io/QuEST/group__matrices__create.html#ga634309472d1edf400174680af0685b89), with many ways to [initialise](https://quest-kit.github.io/QuEST/group__matrices__setters.html) them. +```C++ +CompMatr bigmatrix = createCompMatr(8); +setCompMatr(bigmatrix, {{1,2,3,...}}); +applyCompMatr(qureg, ..., bigmatrix); +``` +Matrix elements can be manually modified, though this requires we [synchronise](https://quest-kit.github.io/QuEST/group__matrices__sync.html) them with GPU memory once finished. +```C++ +qindex dim = bigmatrix.numRows; + +// initialise random diagonal unitary +for (qindex r=0; r [!IMPORTANT] +> The created `CompMatr` is a [heap object](https://craftofcoding.wordpress.com/2015/12/07/memory-in-c-the-stack-the-heap-and-static/) and must be [destroyed](https://quest-kit.github.io/QuEST/group__matrices__destroy.html) when we are finished with it, to free up its memory and avoid leaks. +> ```C++ +> destroyCompMatr(bigmatrix); +> ``` +> This is true of any QuEST structure returned by a `create*()` function. It is _not_ true of functions prefixed with `get*()` with are always [stack variables](https://craftofcoding.wordpress.com/2015/12/07/memory-in-c-the-stack-the-heap-and-static/), hence why functions like `getCompMatr1()` can be called inline! + + +#### `FullStateDiagMatr` + +Above, we initialised [`CompMatr`](https://quest-kit.github.io/QuEST/structCompMatr.html) to a diagonal unitary. This is incredibly wasteful; only `256` of its `65536` elements are non-zero! We should instead use [`DiagMatr`](https://quest-kit.github.io/QuEST/structDiagMatr.html) or [`FullStateDiagMatr`](https://quest-kit.github.io/QuEST/structFullStateDiagMatr.html). The latter is even distributed (if chosen by the autodeployer), permitting it to be as large as a `Qureg` itself! +```C++ +FullStateDiagMatr fullmatrix = createFullStateDiagMatr(qureg.numQubits); +``` +and can be [initialised](https://quest-kit.github.io/QuEST/group__matrices__setters.html) in many ways, including from all-`Z` pauli sums! +```C++ +PauliStrSum sum = createInlinePauliStrSum(R"( + 1 II + 1i ZI + 1i IZ + -1 ZZ +)"); + +setFullStateDiagMatrFromPauliStrSum(fullmatrix, sum); +``` +> [!IMPORTANT] +> The argument to `createInlinePauliStrSum` is a multiline string for which the syntax differs between `C` and `C++`; we used the latter above. See examples [`initialisation.c`](/examples/paulis/initialisation.c) and [`initialisation.cpp`](/paulis/matrices/initialisation.cpp) for clarity. + +> [!CAUTION] +> Beware that in distributed settings, because `fullmatrix` _may_ be distributed, we should must exercise extreme caution when modifying its `fullmatrix.cpuElems` directly. + + +A `FullStateDiagMatr` acts upon all qubits of a qureg +```C++ +applyFullStateDiagMatr(qureg, fullmatrix); +``` +and can be raised to an arbitrary power, helpful for example in simulating [quantum spectral methods](https://www.science.org/doi/10.1126/sciadv.abo7484). +```C++ +qcomp exponent = 3.5; +applyFullStateDiagMatrPower(qureg, fullmatrix, exponent); +``` + +Notice the `exponent` is a `qcomp` and ergo permitted to be a complex number. Unitarity requires `exponent` is strictly real, but we can always relax the unitarity validation... + + +#### validation + + +Our example above initialised `CompMatr` to a diagonal because it is tricky to generate random non-diagonal **_unitary_** matrices - and QuEST checks for unitarity! +```C++ +// m * dagger(m) != identity +CompMatr1 m = getCompMatr1({{.1,.2},{.3,.4}}); +applyCompMatr1(qureg, 0, m); +``` +``` +QuEST encountered a validation error during function 'applyCompMatr1': +The given matrix was not (approximately) unitary. +Exiting... +``` +If we're satisfied our matrix _is_ sufficiently approximately unitary, we can [adjust](https://quest-kit.github.io/QuEST/group__debug__validation.html#gae395568df6def76045ec1881fcb4e6d1) or [disable](https://quest-kit.github.io/QuEST/group__debug__validation.html#ga5999824df0785ea88fb2d5b5582f2b46) the validation. +```C++ +// max(norm(m * dagger(m) - identity)) = 0.9025 +setValidationEpsilon(0.903); +applyCompMatr1(qureg, 0, m); +``` + + +### circuits + +QuEST includes a few convenience functions for effecting [QFT](https://quest-kit.github.io/QuEST/group__op__qft.html) and [Trotter](https://quest-kit.github.io/QuEST/group__op__paulistrsum.html) circuits. + +```C++ +applyQuantumFourierTransform(qureg, targets, 3); + +qreal time = .3; +int order = 4; +int reps = 10; +applyTrotterizedPauliStrSumGadget(qureg, sum, time, order, reps); +``` + + + +### measurements + +We can also effect a wide range of non-unitary operations, such as destructive [measurements](https://quest-kit.github.io/QuEST/group__op__measurement.html) +```C++ +int outcome1 = applyQubitMeasurement(qureg, 0); + +qreal prob; +qindex outcome2 = applyMultiQubitMeasurementAndGetProb(qureg, targets, 3, &prob); +``` +and conveniently [report](https://quest-kit.github.io/QuEST/group__types.html#ga2be8a4433585a8d737c02128b4754a03) their outcome. +```C++ +reportScalar("one qubit outcome", outcome1); +reportScalar("three qubit outcome", outcome2); +``` + +> [!IMPORTANT] +> Notice the type of `outcome2` is a [`qindex`](https://quest-kit.github.io/QuEST/group__types.html#ga6017090d3ed4063ee7233e20c213424b) rather than an `int`. This is a larger type which can store much larger numbers without overflow - up to `2^63` - and is always used by the API for many-qubit indices. + +Should we wish to leave the state unnormalised, we can instead use [projectors](https://quest-kit.github.io/QuEST/group__op__projectors.html). + +### decoherence + +Density matrices created with [`createDensityQureg()`](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga1470424b0836ae18b5baab210aedf5d9) can undergo [decoherence](https://quest-kit.github.io/QuEST/group__decoherence.html) channels. + +```C++ +qreal prob = 0.1; +mixDamping(rho, target, prob); +mixDephasing(rho, target, prob); +mixTwoQubitDepolarising(rho, targets[0], targets[1], prob); +``` +which we can specify as inhomogeneous Pauli channels +```C++ +// passing probabilities of X, Y, Z errors respectively +mixPaulis(Qureg qureg, target, .05, .10, .15); +``` +or completely generally as [Kraus maps](https://quest-kit.github.io/QuEST/group__channels.html) and [superoperators](https://quest-kit.github.io/QuEST/group__channels.html)! +```C++ +int numTargets = 1; +int numOperators = 4; + +qreal p = 0.1; +qreal l = 0.3; + +// generalised amplitude damping +KrausMap map = createInlineKrausMap(numTargets, numOperators, { + { + {sqrt(p), 0}, + {0, sqrt(p*(1-l))} + }, { + {0, sqrt(p*l)}, + {0, 0} + }, { + {sqrt((1-p)*(1-l)), 0}, + {0, sqrt(1-p)} + }, { + {0, 0}, + {sqrt((1-p)*l), 0} + } +}); + +int victims[] = {2}; +mixKrausMap(rho, victims, 1, map); +``` +We can even directy mix density matrices together +```C++ +mixQureg(rho1, rho2, prob); +``` + +Sometimes we wish to left-multiply general operators upon density matrices without also right-multiplying their adjoint - i.e. our operators should _not_ be effected as unitaries. We can do this with the `multiply*()` functions. +```C++ +multiplyDiagMatrPower(rho, fullmatrix, 0.5); +``` + + +## 6. Perform calculations + +After so much modification to our state, we will find that its amplitudes have differed substantially. But it's impractical to observe the exponentially-many amplitudes with [`reportQureg()`](https://quest-kit.github.io/QuEST/group__qureg__report.html#ga2a9df2538e537332b1aef8596ce337b2). We can instead give QuEST the [questions](https://quest-kit.github.io/QuEST/group__calculations.html) we wish to answer about the resulting state. + +For example, we can find the [probability](https://quest-kit.github.io/QuEST/group__calc__prob.html) of measurement outcomes _without_ modifying the state. +```C++ +int outcome = 1; +qreal prob1 = calcProbOfQubitOutcome(qureg, target, outcome); + +int qubits[] = {2,3,4}; +int outcomes[] = {0,1,1}; +qreal prob2 = calcProbOfMultiQubitOutcome(qureg, qubits, outcomes, 3); +``` +We can obtain _all_ outcome probabilities in one swoop: +```C++ +qreal probs[8]; +calcProbsOfAllMultiQubitOutcomes(probs, qureg, qubits, 3); +``` + +> [!TIP] +> `C++` users can also obtain the result as a natural `std::vector`. +> ```C++ +> auto probs = calcProbsOfAllMultiQubitOutcomes(qureg, {2,3,4}); +> ``` + +It is similarly trivial to find [expectation values](https://quest-kit.github.io/QuEST/group__calc__expec.html) +```C++ +qreal expec1 = calcExpecPauliStr(qureg, getPauliStr("XYZIII")); +qreal expec2 = calcExpecPauliStrSum(qureg, sum); +qreal expec3 = calcExpecFullStateDiagMatr(qureg, fullmatrix); +``` +or [distance measures](https://quest-kit.github.io/QuEST/group__calc__comparisons.html) between states, including between statevectors and density matrices. +```C++ +qreal pur = calcPurity(rho); +qreal fid = calcFidelity(rho, psi); +qreal dist = calcDistance(rho, psi); +``` + +We can even find reduced density matrices resulting from [partially tracing](https://quest-kit.github.io/QuEST/group__calc__partialtrace.html) out qubits. +```C++ +Qureg reduced = calcPartialTrace(qureg, targets, 3); + +reportScalar("entanglement", calcPurity(reduced)); +``` + +## 7. Report the results + +We've seen above that [scalars](https://quest-kit.github.io/QuEST/group__types.html) can be reported, handling the pretty formatting of real and complex numbers, controlled by settings like [`setMaxNumReportedSigFigs()`](https://quest-kit.github.io/QuEST/group__debug__reporting.html#ga15d46e5d813f70b587762814964e1994). But we can also report every data structure in the QuEST API, such as Pauli strings +```C++ +reportPauliStr( + getInlinePauliStr("XXYYZZ", {5,50, 10,60, 30,40}) +); +``` +``` +YIIIIIIIIIXIIIIIIIIIZIIIIIIIIIZIIIIIIIIIIIIIIIIIIIYIIIIXIIIII +``` +and their weighted sums +```C++ +reportPauliStrSum(sum); +``` +``` +PauliStrSum (4 terms, 160 bytes): + 1 II + i ZI + i IZ + -1 ZZ +``` +All outputs are affected by the [reporter settings](https://quest-kit.github.io/QuEST/group__debug__reporting.html). +```C++ +setMaxNumReportedItems(4,4); +setMaxNumReportedSigFigs(1); +reportCompMatr(bigmatrix); +``` +``` +CompMatr (8 qubits, 256x256 qcomps, 1 MiB): + 0.9-0.5i 0 … 0 0 + 0 0.8-0.6i … 0 0 + ⋮ + 0 0 … -0.5-0.9i 0 + 0 0 … 0 0.4+0.9i +``` + + + +> [!NOTE] +> Facilities for automatically logging to file are coming soon! + + +## 8. Cleanup + +While not strictly necessary before the program ends, it is a good habit to destroy data structures as soon as you are finished with them, freeing their memory. + +```C++ +destroyQureg(qureg); +destroyCompMatr(bigmatrix); +destroyFullStateDiagMatr(fullmatrix); +destroyPauliStrSum(sum); +destroyKrausMap(map); +``` + +## 9. Finalise QuEST + +The **_final_** [step](https://quest-kit.github.io/QuEST/group__environment.html#ga428faad4d68abab20f662273fff27e39) of our program should be to call +```C++ +finalizeQuESTEnv(); +``` +which ensures everything is synchronised, frees accelerator resources, and finalises MPI. +This is important because it ensures: +- _everything is done_, and that distributed nodes that are still working (e.g. haven't yet logged to their own file) are not interrupted by early termination of another node. +- the MPI process ends gracefully, and doesn't spew out messy errors! +- our GPU processes are killed quickly, freeing resources for other processes. + +> [!CAUTION] +> After calling `finalizeQuESTEnv()`, MPI will close and each if being accessed directly by the user, will enter an undefined state. Subsequent calls to MPI routines may return gibberish, and distributed machines will have lost their ability to communicate. It is recommended to call `finalizeQuESTEnv()` immediately before exiting. + +You are now a QuEST expert 🎉 though there are _many_ more functions in the [API](https://quest-kit.github.io/QuEST/group__api.html) not covered here. Go forth and simulate! \ No newline at end of file From 6923d4c88e5f828d0f0457eb5d2b77b93ebf82ae Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 17:25:29 +0200 Subject: [PATCH 09/24] updating links --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 022e0e7c3..acdccad86 100644 --- a/README.md +++ b/README.md @@ -84,11 +84,8 @@ In particular, QuEST `v4` was made possible through the support of the UK Nation To learn more: - -- visit the [website](https://quest.qtechtheory.org/) -- see some [examples](/examples/) - view the [documentation](#documentation) -- browse the [API](https://quest-kit.github.io/QuEST/group__api.html) +- visit the [website](https://quest.qtechtheory.org/) - read the [whitepaper](https://www.nature.com/articles/s41598-019-47174-9), which featured in Scientific Report's [Top 100 in Physics](https://www.nature.com/collections/ecehgdfcba/) :trophy:
@@ -188,6 +185,7 @@ QuEST supports: Visit the [docs](docs/README.md) to: - [see what's new in v4](docs/v4.md) + - [follow the tutorial](/examples/README.md#tutorial) - [compile with cmake](docs/compile.md) - [find compatible compilers](docs/compilers.md) - [launch your simulations](docs/launch.md) @@ -242,6 +240,7 @@ You can also browse QuEST's extensive [tests](https://quest-kit.github.io/QuEST/ --> Contributers to QuEST should also check out the: + - [contribution guide](docs/contributing.md) - [software architecture](docs/architecture.md) - [style guide](docs/styleguide.md) From 142c785fa4d027990b525d82d989f9071f09aaf7 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 17:25:38 +0200 Subject: [PATCH 10/24] removing header whitespace --- quest/include/operations.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quest/include/operations.h b/quest/include/operations.h index 0f2c0b8e0..ee5506df7 100644 --- a/quest/include/operations.h +++ b/quest/include/operations.h @@ -979,7 +979,7 @@ void applyMultiStateControlledPhaseGadget(Qureg qureg, int* controls, int* state /// @notdoced -void applyPhaseFlip (Qureg qureg, int target); +void applyPhaseFlip(Qureg qureg, int target); /// @notdoced @@ -1047,7 +1047,7 @@ void applyTwoQubitPhaseShift(Qureg qureg, int target1, int target2, qreal angle) /// @notdoced -void applyMultiQubitPhaseFlip (Qureg qureg, int* targets, int numTargets); +void applyMultiQubitPhaseFlip(Qureg qureg, int* targets, int numTargets); /// @notdoced From 8a6c90eb20ec2f862576e2b0a9855ab3ef562f5c Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 17:29:43 +0200 Subject: [PATCH 11/24] put TOC in aesthetic boxes --- docs/compile.md | 38 +++++++++++++++++++------------------- docs/compilers.md | 18 +++++++++--------- docs/launch.md | 44 ++++++++++++++++++++++---------------------- docs/v4.md | 10 +++++----- examples/README.md | 2 +- 5 files changed, 56 insertions(+), 56 deletions(-) diff --git a/docs/compile.md b/docs/compile.md index 46652e44d..081f8773b 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -16,25 +16,25 @@ QuEST can be compiled with [CMake](https://cmake.org/) to make a standalone executable, or an exported library, or a library installed on the system. Compiling is configured with variables supplied by the [`-D` flag](https://cmake.org/cmake/help/latest/command/add_definitions.html) to the [CMake CLI](https://cmake.org/cmake/help/latest/guide/user-interaction/index.html#command-line-cmake-tool). This page details _how_ to compile QuEST for varying purposes and hardwares. -**TOC**: -- [Basic](#basic) -- [Optimising](#optimising) -- [Linking](#linking) -- [Configuring](#configuring) - * [Precision](#precision) - * [Compilers](#compilers) - * [Flags](#flags) -- [Examples](#examples) -- [Tests](#tests) - * [v4](#v4) - * [v3](#v3) -- [Multithreading](#multithreading) -- [GPU-acceleration](#gpu-acceleration) - * [NVIDIA](#nvidia) - * [AMD](#amd) -- [cuQuantum](#cuquantum) -- [Distribution](#distribution) -- [Multi-GPU](#multi-gpu) +> **TOC**: +> - [Basic](#basic) +> - [Optimising](#optimising) +> - [Linking](#linking) +> - [Configuring](#configuring) +> * [Precision](#precision) +> * [Compilers](#compilers) +> * [Flags](#flags) +> - [Examples](#examples) +> - [Tests](#tests) +> * [v4](#v4) +> * [v3](#v3) +> - [Multithreading](#multithreading) +> - [GPU-acceleration](#gpu-acceleration) +> * [NVIDIA](#nvidia) +> * [AMD](#amd) +> - [cuQuantum](#cuquantum) +> - [Distribution](#distribution) +> - [Multi-GPU](#multi-gpu) > **See also**: > - [`cmake.md`](cmake.md) for the full list of passable compiler variables. diff --git a/docs/compilers.md b/docs/compilers.md index 2a71d4167..cc8e1487f 100644 --- a/docs/compilers.md +++ b/docs/compilers.md @@ -11,15 +11,15 @@ QuEST separates compilation of the **_frontend_**, **_backend_** and the **_test This page details the specialised compilers necessary to enable specific features hardware accelerators, and lists such compilers which are known to be compatible with QuEST. -**TOC**: -- [Frontend](#frontend) -- [Backend](#backend) - * [comm](#comm) - * [cpu](#cpu) - * [gpu](#gpu) - * [comm + gpu](#comm-gpu) - * [gpu + cuquantum](#gpu-cuquantum) -- [Tests](#tests) +> **TOC**: +> - [Frontend](#frontend) +> - [Backend](#backend) +> * [comm](#comm) +> * [cpu](#cpu) +> * [gpu](#gpu) +> * [comm + gpu](#comm-gpu) +> * [gpu + cuquantum](#gpu-cuquantum) +> - [Tests](#tests) > **See also**: > - [`compile.md`](compile.md) for a guide to compiling QuEST. diff --git a/docs/launch.md b/docs/launch.md index c4432974d..7a20752eb 100644 --- a/docs/launch.md +++ b/docs/launch.md @@ -8,28 +8,28 @@ Launching your [compiled](compile.md) QuEST application can be as straightforward as running any other executable, though some additional steps are needed to make use of hardware acceleration. This page how to launch your own QuEST applications on different platforms, how to run the examples and unit tests, how to make use of multithreading, GPU-acceleration, distribution and supercomputer job schedulers, and monitor the hardware utilisation. -**TOC**: -- [Examples](#examples) -- [Tests](#tests) - * [v4](#v4) - * [v3](#v3) -- [Multithreading](#multithreading) - * [Choosing threads](#choosing-threads) - * [Monitoring utilisation](#monitoring-utilisation) - * [Improving performance](#improving-performance) -- [GPU-acceleration](#gpu-acceleration) - * [Launching](#launching) - * [Monitoring](#monitoring) - * [Configuring](#configuring) - * [Benchmarking](#benchmarking) -- [Distribution](#distribution) - * [Launching](#launching-1) - * [Configuring](#configuring-1) - * [Benchmarking](#benchmarking-1) -- [Multi-GPU](#multi-gpu) -- [Supercomputers](#supercomputers) - * [SLURM](#slurm) - * [PBS](#pbs) +> **TOC**: +> - [Examples](#examples) +> - [Tests](#tests) +> * [v4](#v4) +> * [v3](#v3) +> - [Multithreading](#multithreading) +> * [Choosing threads](#choosing-threads) +> * [Monitoring utilisation](#monitoring-utilisation) +> * [Improving performance](#improving-performance) +> - [GPU-acceleration](#gpu-acceleration) +> * [Launching](#launching) +> * [Monitoring](#monitoring) +> * [Configuring](#configuring) +> * [Benchmarking](#benchmarking) +> - [Distribution](#distribution) +> * [Launching](#launching-1) +> * [Configuring](#configuring-1) +> * [Benchmarking](#benchmarking-1) +> - [Multi-GPU](#multi-gpu) +> - [Supercomputers](#supercomputers) +> * [SLURM](#slurm) +> * [PBS](#pbs) > [!NOTE] > This page assumes you are working in a `build` directory into which all executables have been compiled. diff --git a/docs/v4.md b/docs/v4.md index 1519668a6..e2ef64e25 100644 --- a/docs/v4.md +++ b/docs/v4.md @@ -3,11 +3,11 @@ QuEST `v4` has completely overhauled the API, software architecture, algorithms, implementations and testing. This page details the new features, divided into those relevant to _users_, _developers_ who integrate QuEST into larger software stacks, and _contributors_ who develop QuEST or otherwise peep at the source code! -**TOC**: -- [For users](#for-users) -- [For developers](#for-developers) -- [For contributors](#for-contributors) -- [Acknowledgements](#acknowledgements) +> **TOC**: +> - [For users](#for-users) +> - [For developers](#for-developers) +> - [For contributors](#for-contributors) +> - [Acknowledgements](#acknowledgements) ## For users diff --git a/examples/README.md b/examples/README.md index 4a2fd619a..29bfb399f 100644 --- a/examples/README.md +++ b/examples/README.md @@ -17,7 +17,7 @@ QuEST is included into a `C` or `C++` project via ``` > [!TIP] -> Some of QuEST's deprecated `v3` API can be accessed by specifying `ENABLE_DEPRECATED_API` when [compiling](/docs/compile.md), or defining it before import, i.e. +> Some of QuEST's deprecated `v3` API can be accessed by specifying `ENABLE_DEPRECATED_API` when [compiling](/docs/compile.md#v3), or defining it before import, i.e. > ```C++ > #define ENABLE_DEPRECATED_API 1 > #include "quest.h" From e637e44262b0ff7da56748f3ff11264887ea47c9 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 17:33:40 +0200 Subject: [PATCH 12/24] style change --- examples/README.md | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/examples/README.md b/examples/README.md index 29bfb399f..0aa200790 100644 --- a/examples/README.md +++ b/examples/README.md @@ -190,19 +190,21 @@ void myErrorHandler(const char *func, const char *msg) { setInputErrorHandler(myErrorHandler); ``` -`C++` users may prefer to throw an exception which can be caught, safely permitting execution to continue. In such cases, the erroneous function will _never_ corrupt any passed inputs like `Qureg` nor matrices, nor cause leaks. -```C++ -#include -#include - -void myErrorHandlerA(const char* errFunc, const char* errMsg) { - std::string func(errFunc); - std::string msg(errMsg); - throw std::runtime_error(func + ": " + msg); -} -setInputErrorHandler(myErrorHandler); -``` +> [!TIP] +> `C++` users may prefer to throw an exception which can be caught, safely permitting execution to continue. In such cases, the erroneous function will _never_ corrupt any passed inputs like `Qureg` nor matrices, nor cause leaks. +> ```C++ +> #include +> #include +> +> void myErrorHandlerA(const char* errFunc, const char* errMsg) { +> std::string func(errFunc); +> std::string msg(errMsg); +> throw std::runtime_error(func + ": " + msg); +> } +> +> setInputErrorHandler(myErrorHandler); +> ``` ## 3. Create a `Qureg` @@ -297,7 +299,7 @@ In lieu of a statevector, we could create a [density matrix](https://quest-kit.g ```C++ Qureg qureg = createDensityQureg(10); ``` -which is also auto-deployed. Note this contains _square_ as many amplitudes as the equal-dimensin statevector, and ergo requires _square_ as much memory. +which is also auto-deployed. Note this contains _square_ as many amplitudes as the equal-dimension statevector and ergo requires _square_ as much memory. ```C++ reportQureg(qureg); reportQuregParams(qureg); From d094a1a640916bad00fc15f9d3327265ca741431 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 18:25:09 +0200 Subject: [PATCH 13/24] marking macros needing separate doc because of the doxygen limitation discussed in stackoverflow.com/questions/79548865 --- quest/include/channels.h | 18 ++++-------- quest/include/matrices.h | 60 +++++++++++++++------------------------ quest/include/paulis.h | 9 ++---- quest/include/precision.h | 18 +++++++++++- quest/include/types.h | 14 +++++++-- utils/docs/Doxyfile | 1 + 6 files changed, 62 insertions(+), 58 deletions(-) diff --git a/quest/include/channels.h b/quest/include/channels.h index 5dd62cc13..a23da0274 100644 --- a/quest/include/channels.h +++ b/quest/include/channels.h @@ -335,16 +335,14 @@ extern "C" { // C then overloads setKrausMap() to call the above VLA when given arrays, using C11 Generics. // See the doc of getCompMatr1() in matrices.h for an explanation of Generic, and its nuances. - /// @ingroup channels_setters - /// @notdoced + /// @neverdoced #define setKrausMap(map, ...) \ _Generic((__VA_ARGS__), \ qcomp*** : setKrausMap, \ default : _setKrausMapFromArr \ )((map), (__VA_ARGS__)) - /// @ingroup channels_setters - /// @notdoced + /// @neverdoced #define setSuperOp(op, ...) \ _Generic((__VA_ARGS__), \ qcomp** : setSuperOp, \ @@ -422,14 +420,12 @@ extern "C" { } - /// @ingroup channels_setters - /// @notdoced + /// @neverdoced #define setInlineKrausMap(map, numQb, numOps, ...) \ _setInlineKrausMap((map), (numQb), (numOps), (qcomp[(numOps)][1<<(numQb)][1<<(numQb)]) __VA_ARGS__) - /// @ingroup channels_setters - /// @notdoced + /// @neverdoced #define setInlineSuperOp(matr, numQb, ...) \ _setInlineSuperOp((matr), (numQb), (qcomp[1<<(2*(numQb))][1<<(2*(numQb))]) __VA_ARGS__) @@ -499,14 +495,12 @@ extern "C" { } - /// @ingroup channels_create - /// @notdoced + /// @neverdoced #define createInlineKrausMap(numQb, numOps, ...) \ _createInlineKrausMap((numQb), (numOps), (qcomp[(numOps)][1<<(numQb)][1<<(numQb)]) __VA_ARGS__) - /// @ingroup channels_create - /// @notdoced + /// @neverdoced #define createInlineSuperOp(numQb, ...) \ _createInlineSuperOp((numQb), (qcomp[1<<(2*(numQb))][1<<(2*(numQb))]) __VA_ARGS__) diff --git a/quest/include/matrices.h b/quest/include/matrices.h index c613a6607..40cd00b7c 100644 --- a/quest/include/matrices.h +++ b/quest/include/matrices.h @@ -471,8 +471,7 @@ static inline CompMatr2 _getCompMatr2FromArr(qcomp in[4][4]) { // e.g. default: _Pragma("GCC error \"arg not allowed\""). - /// @ingroup matrices_getters - /// @notdoced + /// @neverdoced #define getCompMatr1(...) \ _Generic((__VA_ARGS__), \ qcomp** : getCompMatr1, \ @@ -480,8 +479,7 @@ static inline CompMatr2 _getCompMatr2FromArr(qcomp in[4][4]) { )((__VA_ARGS__)) - /// @ingroup matrices_getters - /// @notdoced + /// @neverdoced #define getCompMatr2(...) \ _Generic((__VA_ARGS__), \ qcomp** : getCompMatr2, \ @@ -510,26 +508,22 @@ static inline CompMatr2 _getCompMatr2FromArr(qcomp in[4][4]) { // C++ merely invokes the std::vector initialiser overload - /// @ingroup matrices_getters - /// @notdoced + /// @neverdoced #define getInlineCompMatr1(...) \ getCompMatr1(__VA_ARGS__) - /// @ingroup matrices_getters - /// @notdoced + /// @neverdoced #define getInlineCompMatr2(...) \ getCompMatr2(__VA_ARGS__) - /// @ingroup matrices_getters - /// @notdoced + /// @neverdoced #define getInlineDiagMatr1(...) \ getDiagMatr1(__VA_ARGS__) - /// @ingroup matrices_getters - /// @notdoced + /// @neverdoced #define getInlineDiagMatr2(...) \ getDiagMatr2(__VA_ARGS__) @@ -539,26 +533,22 @@ static inline CompMatr2 _getCompMatr2FromArr(qcomp in[4][4]) { // explicitly specifying the DiagMatr dimension enables defaulting-to-zero - /// @ingroup matrices_getters - /// @notdoced + /// @neverdoced #define getInlineCompMatr1(...) \ _getCompMatr1FromArr((qcomp[2][2]) __VA_ARGS__) - /// @ingroup matrices_getters - /// @notdoced + /// @neverdoced #define getInlineCompMatr2(...) \ _getCompMatr2FromArr((qcomp[4][4]) __VA_ARGS__) - /// @ingroup matrices_getters - /// @notdoced + /// @neverdoced #define getInlineDiagMatr1(...) \ getDiagMatr1((qcomp[2]) __VA_ARGS__) - /// @ingroup matrices_getters - /// @notdoced + /// @neverdoced #define getInlineDiagMatr2(...) \ getDiagMatr2((qcomp[4]) __VA_ARGS__) @@ -749,8 +739,7 @@ extern "C" { // See the doc of getCompMatr1() above for an explanation of Generic, and its nuances - /// @ingroup matrices_setters - /// @notdoced + /// @neverdoced #define setCompMatr(matr, ...) \ _Generic((__VA_ARGS__), \ qcomp** : setCompMatr, \ @@ -848,24 +837,25 @@ extern "C" { // unexpectedly re-evaluating user expressions due to its repetition in the macro - /// @ingroup matrices_setters - /// @notdoced + /// @neverdoced #define setInlineCompMatr(matr, numQb, ...) \ _setInlineCompMatr((matr), (numQb), (qcomp[1<<(numQb)][1<<(numQb)]) __VA_ARGS__) - /// @ingroup matrices_setters - /// @notdoced + /// @neverdoced #define setInlineDiagMatr(matr, numQb, ...) \ _setInlineDiagMatr((matr), (numQb), (qcomp[1<<(numQb)]) __VA_ARGS__) - /// @ingroup matrices_setters - /// @notdoced - /// @nottested + /// @neverdoced #define setInlineFullStateDiagMatr(matr, startInd, numElems, ...) \ _setInlineFullStateDiagMatr((matr), (startInd), (numElems), (qcomp[(numElems)]) __VA_ARGS__) + + // TODO: + // beware above is not tested!!! Must note this in new doc + + #else // MSVC C11 does not support C99 VLAs, so the inner functions above are illegal. @@ -887,8 +877,7 @@ extern "C" { extern void _validateParamsToSetInlineFullStateDiagMatr(FullStateDiagMatr matr, qindex startInd, qindex numElems); - /// @ingroup matrices_setters - /// @notdoced + /// @neverdoced #define setInlineDiagMatr(matr, numQb, ...) \ do { \ _validateParamsToSetInlineDiagMatr((matr), (numQb)); \ @@ -896,8 +885,7 @@ extern "C" { } while (0) - /// @ingroup matrices_setters - /// @notdoced + /// @neverdoced #define setInlineFullStateDiagMatr(matr, startInd, numElems, ...) \ do { \ _validateParamsToSetInlineFullStateDiagMatr((matr), (startInd), (numElems)); \ @@ -971,14 +959,12 @@ extern "C" { } - /// @ingroup matrices_create - /// @notdoced + /// @neverdoced #define createInlineCompMatr(numQb, ...) \ _createInlineCompMatr((numQb), (qcomp[1<<(numQb)][1<<(numQb)]) __VA_ARGS__) - /// @ingroup matrices_create - /// @notdoced + /// @neverdoced #define createInlineDiagMatr(numQb, ...) \ _createInlineDiagMatr((numQb), (qcomp[1<<(numQb)]) __VA_ARGS__) diff --git a/quest/include/paulis.h b/quest/include/paulis.h index 09b4220ae..c88384c0c 100644 --- a/quest/include/paulis.h +++ b/quest/include/paulis.h @@ -141,8 +141,7 @@ typedef struct { PauliStr getPauliStr(std::string paulis); - /// @ingroup paulis_create - /// @notdoced + /// @neverdoced #define getInlinePauliStr(str, ...) \ getPauliStr(str, __VA_ARGS__) @@ -167,8 +166,7 @@ typedef struct { PauliStr _getPauliStrFromInts(int* paulis, int* indices, int numPaulis); - /// @ingroup paulis_create - /// @notdoced + /// @neverdoced #define getPauliStr(paulis, ...) \ _Generic((paulis), \ int* : _getPauliStrFromInts, \ @@ -176,8 +174,7 @@ typedef struct { )(paulis, __VA_ARGS__) - /// @ingroup paulis_create - /// @notdoced + /// @neverdoced #define getInlinePauliStr(str, ...) \ getPauliStr((str), (int[sizeof(str)-1]) __VA_ARGS__, sizeof(str)-1) diff --git a/quest/include/precision.h b/quest/include/precision.h index b39a18fad..3d5fa2eeb 100644 --- a/quest/include/precision.h +++ b/quest/include/precision.h @@ -30,6 +30,8 @@ // benefit in shrinking the type size and facing the associated precision risks. Similarly, // there is little benefit in making it larger since a 'long long int' can represent 62 qubits, // which is already well beyond simulability, requiring 64 EiB total at double precision. + +/// @neverdoced #define INDEX_TYPE long long int @@ -45,6 +47,8 @@ // base-4 numeral encoding the Pauli string. A single 64-bit 'long long unsigned' can ergo // specify only 32 qubits, whereas two can specify more qubits (64) than we can simulate. // This type is defined purely to avoid littering the source with explicit typing. + +/// @neverdoced #define PAULI_MASK_TYPE long long unsigned int @@ -53,6 +57,12 @@ * RE-CONFIGURABLE FLOATING-POINT PRECISION */ +/// @neverdoced +/// @fn FLOAT_PRECISION + +/// @neverdoced +/// @fn FLOAT_TYPE + // assume double precision as default #ifndef FLOAT_PRECISION #define FLOAT_PRECISION 2 @@ -61,7 +71,7 @@ // validate precision is 1 (float), 2 (double) or 4 (long double) #if ! (FLOAT_PRECISION == 1 || FLOAT_PRECISION == 2 || FLOAT_PRECISION == 4) #error "FLOAT_PRECISION must be 1 (float), 2 (double) or 4 (long double)" -#endif +#endif // infer floating-point type from precision #if FLOAT_PRECISION == 1 @@ -92,6 +102,9 @@ * compiler using argument -D), and runtime overridable using setValidationEpsilon() */ +/// @neverdoced +/// @fn DEFAULT_VALIDATION_EPSILON + #ifndef DEFAULT_VALIDATION_EPSILON #if FLOAT_PRECISION == 1 @@ -113,6 +126,9 @@ * PRECISION-AGNOSTIC CONVENIENCE MACROS */ +/// @neverdoced +/// @fn QREAL_FORMAT_SPECIFIER + #if FLOAT_PRECISION == 1 #define QREAL_FORMAT_SPECIFIER "%.8g" diff --git a/quest/include/types.h b/quest/include/types.h index a04350982..5b347e5e3 100644 --- a/quest/include/types.h +++ b/quest/include/types.h @@ -164,6 +164,9 @@ static inline qcomp getQcomp(qreal re, qreal im) { // no doubt break somebody's build/integration, users can disable this // attempt at precision-agnostic arithmetic via DEFINE_ARITHMETIC_OVERLOADS=0 + /// @neverdoced + /// @fn DEFINE_ARITHMETIC_OVERLOADS + #ifndef DEFINE_ARITHMETIC_OVERLOADS #define DEFINE_ARITHMETIC_OVERLOADS 1 #endif @@ -288,22 +291,27 @@ static inline qcomp getQcomp(qreal re, qreal im) { /// @nottested extern "C" void reportStr(const char* str); + /// @notdoced /// @nottested void reportStr(std::string str); + /// @notdoced /// @nottested extern "C" void reportScalar(const char* label, qcomp num); + /// @notdoced /// @nottested void reportScalar(const char* label, qreal num); + /// @notdoced /// @nottested void reportScalar(std::string label, qcomp num); + /// @notdoced /// @nottested void reportScalar(std::string label, qreal num); @@ -314,15 +322,17 @@ static inline qcomp getQcomp(qreal re, qreal im) { /// @nottested void reportStr(const char* str); + /// @notdoced /// @nottested void reportScalar (const char* label, qcomp num); + /// @private void _reportScalar_real(const char* label, qreal num); - /// @notdoced - /// @nottested + + /// @neverdoced #define reportScalar(label, num) \ _Generic((num), \ qcomp : reportScalar, \ diff --git a/utils/docs/Doxyfile b/utils/docs/Doxyfile index 435c03e8f..0e0748a1e 100644 --- a/utils/docs/Doxyfile +++ b/utils/docs/Doxyfile @@ -299,6 +299,7 @@ ALIASES += "nottested=@warning This function has not yet been unit tested and ma 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 += "cpponly=@remark This function is only available in C++." +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 += "constraints=@par Constraints" From b1a78cd89e064cbb1c71adf7ee8c1ab22e8dd183 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 20:03:49 +0200 Subject: [PATCH 14/24] exposed macros to doxygen via regrettable workaround in https://stackoverflow.com/questions/79548865/ --- quest/include/channels.h | 49 ++++++++++++++++++- quest/include/matrices.h | 99 ++++++++++++++++++++++++++++++++++----- quest/include/paulis.h | 42 ++++++++++++----- quest/include/precision.h | 62 +++++++++++++++++++----- quest/include/types.h | 27 +++++++---- utils/docs/Doxyfile | 2 + 6 files changed, 236 insertions(+), 45 deletions(-) diff --git a/quest/include/channels.h b/quest/include/channels.h index a23da0274..e9a1e33bc 100644 --- a/quest/include/channels.h +++ b/quest/include/channels.h @@ -349,6 +349,24 @@ extern "C" { default : _setSuperOpFromArr \ )((op), (__VA_ARGS__)) + // spoofing macros as functions + #if 0 + + /// @ingroup channels_setters + /// @notdoced + /// @conly + /// @macrodoc + void setKrausMap(KrausMap map, qcomp matrices[map.numMatrices][map.numRows][map.numRows]); + + /// @ingroup channels_setters + /// @notdoced + /// @conly + /// @macrodoc + void setSuperOp(SuperOp op, qcomp matrix[op.numRows][op.numRows]); + + #endif + + #else // MSVC's C11 does not support C99 VLAs, so there is no way to support _setKrausMapFromArr(), @@ -429,6 +447,21 @@ extern "C" { #define setInlineSuperOp(matr, numQb, ...) \ _setInlineSuperOp((matr), (numQb), (qcomp[1<<(2*(numQb))][1<<(2*(numQb))]) __VA_ARGS__) + // spoofing macros as functions + #if 0 + + /// @ingroup channels_setters + /// @notdoced + /// @macrodoc + void setInlineKrausMap(KrausMap map, int numQb, int numOps, {{{ matrices }}}); + + /// @ingroup channels_setters + /// @notdoced + /// @macrodoc + void setInlineSuperOp(SuperOp op, int numQb, {{ matrix }}); + + #endif + #else // MSVC's C11 does not support C99 VLA, so the inner *FromArr() functions have not @@ -499,11 +532,25 @@ extern "C" { #define createInlineKrausMap(numQb, numOps, ...) \ _createInlineKrausMap((numQb), (numOps), (qcomp[(numOps)][1<<(numQb)][1<<(numQb)]) __VA_ARGS__) - /// @neverdoced #define createInlineSuperOp(numQb, ...) \ _createInlineSuperOp((numQb), (qcomp[1<<(2*(numQb))][1<<(2*(numQb))]) __VA_ARGS__) + // spoofing macros as functions + #if 0 + + /// @ingroup channels_create + /// @notdoced + /// @macrodoc + KrausMap createInlineKrausMap(int numQb, int numOps, {{{ matrices }}}); + + /// @ingroup channels_create + /// @notdoced + /// @macrodoc + SuperOp createInlineSuperOp(int numQb, {{ matrix }}); + + #endif + #else // MSVC's C11 does not support C99 VLA, so none of the necessary inner functions are defined, diff --git a/quest/include/matrices.h b/quest/include/matrices.h index 40cd00b7c..d901623fb 100644 --- a/quest/include/matrices.h +++ b/quest/include/matrices.h @@ -486,6 +486,10 @@ static inline CompMatr2 _getCompMatr2FromArr(qcomp in[4][4]) { default : _getCompMatr2FromArr \ )((__VA_ARGS__)) + + // note the above macros do not need explicit, separate doxygen + // doc because the C++ overloads above it have identical signatures + #endif @@ -507,22 +511,18 @@ static inline CompMatr2 _getCompMatr2FromArr(qcomp in[4][4]) { // C++ merely invokes the std::vector initialiser overload - /// @neverdoced #define getInlineCompMatr1(...) \ getCompMatr1(__VA_ARGS__) - /// @neverdoced #define getInlineCompMatr2(...) \ getCompMatr2(__VA_ARGS__) - /// @neverdoced #define getInlineDiagMatr1(...) \ getDiagMatr1(__VA_ARGS__) - /// @neverdoced #define getInlineDiagMatr2(...) \ getDiagMatr2(__VA_ARGS__) @@ -532,26 +532,46 @@ static inline CompMatr2 _getCompMatr2FromArr(qcomp in[4][4]) { // C adds compound literal syntax to make a temporary array. Helpfully, // explicitly specifying the DiagMatr dimension enables defaulting-to-zero - /// @neverdoced #define getInlineCompMatr1(...) \ _getCompMatr1FromArr((qcomp[2][2]) __VA_ARGS__) - /// @neverdoced #define getInlineCompMatr2(...) \ _getCompMatr2FromArr((qcomp[4][4]) __VA_ARGS__) - /// @neverdoced #define getInlineDiagMatr1(...) \ getDiagMatr1((qcomp[2]) __VA_ARGS__) - /// @neverdoced #define getInlineDiagMatr2(...) \ getDiagMatr2((qcomp[4]) __VA_ARGS__) +#endif + +// spoofing above macros as functions to doc +#if 0 + + /// @ingroup matrices_getters + /// @notdoced + /// @macrodoc + CompMatr1 getInlineCompMatr1({{ matrix }}); + + /// @ingroup matrices_getters + /// @notdoced + /// @macrodoc + CompMatr2 getInlineCompMatr2({{ matrix }}); + + /// @ingroup matrices_getters + /// @notdoced + /// @macrodoc + DiagMatr1 getInlineDiagMatr1({ list }); + + /// @ingroup matrices_getters + /// @notdoced + /// @macrodoc + DiagMatr2 getInlineDiagMatr2({ list }); #endif @@ -746,6 +766,17 @@ extern "C" { default : _setCompMatrFromArr \ )((matr), (__VA_ARGS__)) + // spoofing above macro as functions to doc + #if 0 + + /// @ingroup matrices_setters + /// @notdoced + /// @macrodoc + /// @conly + void setCompMatr(CompMatr matr, qcomp arr[matr.numRows][matr.numRows]); + + #endif + // no need to define bespoke overload for diagonal matrices, because 1D arrays decay to pointers @@ -780,17 +811,20 @@ extern "C" { /// @ingroup matrices_setters /// @notdoced + /// @cpponly void setInlineCompMatr(CompMatr matr, int numQb, std::vector> in); /// @ingroup matrices_setters /// @notdoced + /// @cpponly void setInlineDiagMatr(DiagMatr matr, int numQb, std::vector in); /// @ingroup matrices_setters /// @notdoced /// @nottested + /// @cpponly void setInlineFullStateDiagMatr(FullStateDiagMatr matr, qindex startInd, qindex numElems, std::vector in); @@ -841,19 +875,34 @@ extern "C" { #define setInlineCompMatr(matr, numQb, ...) \ _setInlineCompMatr((matr), (numQb), (qcomp[1<<(numQb)][1<<(numQb)]) __VA_ARGS__) - /// @neverdoced #define setInlineDiagMatr(matr, numQb, ...) \ _setInlineDiagMatr((matr), (numQb), (qcomp[1<<(numQb)]) __VA_ARGS__) - /// @neverdoced #define setInlineFullStateDiagMatr(matr, startInd, numElems, ...) \ _setInlineFullStateDiagMatr((matr), (startInd), (numElems), (qcomp[(numElems)]) __VA_ARGS__) + // spoofing above macros as functions to doc + #if 0 + + /// @ingroup matrices_setters + /// @notdoced + /// @macrodoc + void setInlineCompMatr(CompMatr matr, int numQb, {{ matrix }}); + + /// @ingroup matrices_setters + /// @notdoced + /// @macrodoc + void setInlineDiagMatr(DiagMatr matr, int numQb, { list }); + + /// @ingroup matrices_setters + /// @nottested + /// @notdoced + /// @macrodoc + void setInlineFullStateDiagMatr(FullStateDiagMatr matr, qindex startInd, qindex numElems, { list }); - // TODO: - // beware above is not tested!!! Must note this in new doc + #endif #else @@ -892,6 +941,9 @@ extern "C" { setFullStateDiagMatr((matr), (startInd), (elems), (numElems)); \ } while (0) + + // the above macros are documented in the previous #if branch + #endif @@ -918,11 +970,13 @@ extern "C" { /// @ingroup matrices_create /// @notdoced + /// @cpponly CompMatr createInlineCompMatr(int numQb, std::vector> elems); /// @ingroup matrices_create /// @notdoced + /// @cpponly DiagMatr createInlineDiagMatr(int numQb, std::vector elems); @@ -963,11 +1017,25 @@ extern "C" { #define createInlineCompMatr(numQb, ...) \ _createInlineCompMatr((numQb), (qcomp[1<<(numQb)][1<<(numQb)]) __VA_ARGS__) - /// @neverdoced #define createInlineDiagMatr(numQb, ...) \ _createInlineDiagMatr((numQb), (qcomp[1<<(numQb)]) __VA_ARGS__) + // spoofing above macros as functions to doc + #if 0 + + /// @ingroup matrices_create + /// @notdoced + /// @macrodoc + CompMatr createInlineCompMatr(int numQb, {{ matrix }}); + + /// @ingroup matrices_create + /// @notdoced + /// @macrodoc + DiagMatr createInlineDiagMatr(int numQb, { list }); + + #endif + #else // MSVC's C11 does not support C99 VLA, so we cannot use the above inner functions. @@ -988,6 +1056,11 @@ extern "C" { #endif + /// @todo + /// add std::vector overloads for C++ users for the + /// below functions (missed during original overload work) + + /// @ingroup matrices_setters /// @notdoced /// @nottested diff --git a/quest/include/paulis.h b/quest/include/paulis.h index c88384c0c..a04ed39eb 100644 --- a/quest/include/paulis.h +++ b/quest/include/paulis.h @@ -101,9 +101,23 @@ typedef struct { */ +// base method is C and C++ compatible #ifdef __cplusplus +extern "C" { +#endif + + /// @ingroup paulis_create + /// @notdoced + PauliStr getPauliStr(const char* paulis, int* indices, int numPaulis); + +#ifdef __cplusplus +} +#endif + - // C++ users can access the base C method, along with direct overloads +#ifdef __cplusplus + + // C++ users can access the above C method, along with direct overloads // to accept integers (in lieu of chars), natural C++ string types // (like literals), and C++ vector types for brevity. Furthermore, C++ // gets an overload which accepts only a string (no additional args) @@ -113,11 +127,6 @@ typedef struct { // {0,3,1} are valid std::string instances, causing overload ambiguity. Blegh! - /// @ingroup paulis_create - /// @notdoced - extern "C" PauliStr getPauliStr(const char* paulis, int* indices, int numPaulis); - - /// @ingroup paulis_create /// @notdoced PauliStr getPauliStr(int* paulis, int* indices, int numPaulis); @@ -141,6 +150,8 @@ typedef struct { PauliStr getPauliStr(std::string paulis); + // never needs to be doc'd + /// @private /// @neverdoced #define getInlinePauliStr(str, ...) \ getPauliStr(str, __VA_ARGS__) @@ -156,16 +167,12 @@ typedef struct { // many elements as claimed, avoiding seg-faults if the user provides too few indices - /// @ingroup paulis_create - /// @notdoced - PauliStr getPauliStr(const char* paulis, int* indices, int numPaulis); - - /// @ingroup paulis_create /// @private PauliStr _getPauliStrFromInts(int* paulis, int* indices, int numPaulis); + // documented above (identical signatures to C) /// @neverdoced #define getPauliStr(paulis, ...) \ _Generic((paulis), \ @@ -174,10 +181,21 @@ typedef struct { )(paulis, __VA_ARGS__) + // documented below /// @neverdoced #define getInlinePauliStr(str, ...) \ getPauliStr((str), (int[sizeof(str)-1]) __VA_ARGS__, sizeof(str)-1) + // spoofing above macro as function to doc + #if 0 + + /// @ingroup paulis_create + /// @notdoced + /// @macrodoc + PauliStr getInlinePauliStr(const char* paulis, { list }); + + #endif + #endif @@ -246,6 +264,7 @@ extern "C" { /// @cpponly PauliStrSum createPauliStrSumFromReversedFile(std::string fn); + #endif @@ -265,6 +284,7 @@ extern "C" { /// @notdoced void destroyPauliStrSum(PauliStrSum sum); + // end de-mangler #ifdef __cplusplus } diff --git a/quest/include/precision.h b/quest/include/precision.h index 3d5fa2eeb..b4540b3fc 100644 --- a/quest/include/precision.h +++ b/quest/include/precision.h @@ -30,10 +30,20 @@ // benefit in shrinking the type size and facing the associated precision risks. Similarly, // there is little benefit in making it larger since a 'long long int' can represent 62 qubits, // which is already well beyond simulability, requiring 64 EiB total at double precision. +// Still, we use a #define, rather than a typedef, so that the value can be compile-time overridden. /// @neverdoced #define INDEX_TYPE long long int +// spoofing above macro as const to doc +#if 0 + + /// @notdoced + /// @macrodoc + typedef long long int INDEX_TYPE; + +#endif + /* @@ -51,18 +61,21 @@ /// @neverdoced #define PAULI_MASK_TYPE long long unsigned int +// spoofing above macro as typedef to doc +#if 0 + + /// @notdoced + /// @macrodoc + typedef long long unsigned int PAULI_MASK_TYPE; + +#endif + /* * RE-CONFIGURABLE FLOATING-POINT PRECISION */ -/// @neverdoced -/// @fn FLOAT_PRECISION - -/// @neverdoced -/// @fn FLOAT_TYPE - // assume double precision as default #ifndef FLOAT_PRECISION #define FLOAT_PRECISION 2 @@ -82,6 +95,19 @@ #define FLOAT_TYPE long double #endif +// spoofing above macros as typedefs and consts to doc +#if 0 + + /// @notdoced + /// @macrodoc + const int FLOAT_PRECISION = 2; + + /// @notdoced + /// @macrodoc + typedef double int FLOAT_TYPE; + +#endif + /* @@ -102,9 +128,6 @@ * compiler using argument -D), and runtime overridable using setValidationEpsilon() */ -/// @neverdoced -/// @fn DEFAULT_VALIDATION_EPSILON - #ifndef DEFAULT_VALIDATION_EPSILON #if FLOAT_PRECISION == 1 @@ -120,15 +143,21 @@ #endif +// spoofing above macros as typedefs and consts to doc +#if 0 + + /// @notdoced + /// @macrodoc + const qreal DEFAULT_VALIDATION_EPSILON = 1E-12; + +#endif + /* * PRECISION-AGNOSTIC CONVENIENCE MACROS */ -/// @neverdoced -/// @fn QREAL_FORMAT_SPECIFIER - #if FLOAT_PRECISION == 1 #define QREAL_FORMAT_SPECIFIER "%.8g" @@ -140,6 +169,15 @@ #endif +// spoofing above macros as typedefs and consts to doc +#if 0 + + /// @notdoced + /// @macrodoc + const char* QREAL_FORMAT_SPECIFIER = "%.14g"; + +#endif + #endif // PRECISION_H diff --git a/quest/include/types.h b/quest/include/types.h index 5b347e5e3..b7ea5550e 100644 --- a/quest/include/types.h +++ b/quest/include/types.h @@ -145,8 +145,6 @@ static inline qcomp getQcomp(qreal re, qreal im) { // C11 arithmetic is already defined in complex header, and beautifully // permits mixing of parameterised types and precisions -/// @cond EXCLUDE_FROM_DOXYGEN - #ifdef __cplusplus // defines overloads between complex and same-precision floats, @@ -164,15 +162,24 @@ static inline qcomp getQcomp(qreal re, qreal im) { // no doubt break somebody's build/integration, users can disable this // attempt at precision-agnostic arithmetic via DEFINE_ARITHMETIC_OVERLOADS=0 - /// @neverdoced - /// @fn DEFINE_ARITHMETIC_OVERLOADS - #ifndef DEFINE_ARITHMETIC_OVERLOADS #define DEFINE_ARITHMETIC_OVERLOADS 1 #endif + // spoofing above macro as const to doc + #if 0 + + /// @notdoced + /// @macrodoc + const int DEFINE_ARITHMETIC_OVERLOADS = 1; + + #endif + + #if DEFINE_ARITHMETIC_OVERLOADS + /// @cond EXCLUDE_FROM_DOXYGEN + // shortcuts for below overload definitions #define COMP_TO_QCOMP(a) \ qcomp( \ @@ -265,12 +272,12 @@ static inline qcomp getQcomp(qreal re, qreal im) { #undef DEFINE_ARITHMETIC_BETWEEN_COMPLEX_AND_COMPLEX #undef DEFINE_SINGLE_DIRECTION_ARITHMETIC_BETWEEN_COMPLEX_AND_COMPLEX + /// @endcond // EXCLUDE_FROM_DOXYGEN + #endif // DEFINE_ARITHMETIC_OVERLOADS #endif -/// @endcond // EXCLUDE_FROM_DOXYGEN - /* @@ -294,6 +301,7 @@ static inline qcomp getQcomp(qreal re, qreal im) { /// @notdoced /// @nottested + /// @cpponly void reportStr(std::string str); @@ -309,11 +317,13 @@ static inline qcomp getQcomp(qreal re, qreal im) { /// @notdoced /// @nottested + /// @cpponly void reportScalar(std::string label, qcomp num); /// @notdoced /// @nottested + /// @cpponly void reportScalar(std::string label, qreal num); #else @@ -325,13 +335,14 @@ static inline qcomp getQcomp(qreal re, qreal im) { /// @notdoced /// @nottested - void reportScalar (const char* label, qcomp num); + void reportScalar(const char* label, qcomp num); /// @private void _reportScalar_real(const char* label, qreal num); + // no need to be doc'd since signatures identical to C++ above /// @neverdoced #define reportScalar(label, num) \ _Generic((num), \ diff --git a/utils/docs/Doxyfile b/utils/docs/Doxyfile index 0e0748a1e..8db618737 100644 --- a/utils/docs/Doxyfile +++ b/utils/docs/Doxyfile @@ -299,6 +299,8 @@ ALIASES += "nottested=@warning This function has not yet been unit tested and ma 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 += "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" From e2686ae088b3838afd09d9135bd04fcd1d9b6f2c Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 20:24:38 +0200 Subject: [PATCH 15/24] added missed macros --- quest/include/modes.h | 21 +++++++++++++++++++++ tests/utils/macros.hpp | 17 +++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/quest/include/modes.h b/quest/include/modes.h index 49c5f8d43..61eaf77b4 100644 --- a/quest/include/modes.h +++ b/quest/include/modes.h @@ -89,6 +89,27 @@ // further macros are defined in precision.h +// spoofing above macro as consts to doc +#if 0 + + + /// @notdoced + /// @macrodoc + const int PERMIT_NODES_TO_SHARE_GPU = 0; + + + /// @notdoced + /// @macrodoc + const int INCLUDE_DEPRECATED_FUNCTIONS = 0; + + + /// @notdoced + /// @macrodoc + const int DISABLE_DEPRECATION_WARNINGS = 0; + + +#endif + // user flags for choosing automatic deployment; only accessible by C++ diff --git a/tests/utils/macros.hpp b/tests/utils/macros.hpp index 2a1cc28f5..7d5882051 100644 --- a/tests/utils/macros.hpp +++ b/tests/utils/macros.hpp @@ -47,6 +47,23 @@ #define TEST_NUM_MIXED_DEPLOYMENT_REPETITIONS 10 #endif +// spoofing above macros as consts to doc +#if 0 + + /// @macrodoc + const int TEST_MAX_NUM_QUBIT_PERMUTATIONS = 0; + + /// @macrodoc + const int TEST_MAX_NUM_SUPEROP_TARGETS = 4; + + /// @macrodoc + const int TEST_ALL_DEPLOYMENTS = 1; + + /// @macrodoc + const int TEST_NUM_MIXED_DEPLOYMENT_REPETITIONS = 10; + +#endif + /* * preconditions to the internal unit testing functions are checked using From 8e676605f02ed9e6c71977c44229d4edb63cf077 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 20:33:56 +0200 Subject: [PATCH 16/24] added missing C++-only tags --- quest/include/channels.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/quest/include/channels.h b/quest/include/channels.h index e9a1e33bc..b8c36799b 100644 --- a/quest/include/channels.h +++ b/quest/include/channels.h @@ -399,11 +399,13 @@ extern "C" { /// @ingroup channels_setters /// @notdoced + /// @cpponly void setInlineKrausMap(KrausMap map, int numQb, int numOps, std::vector>> matrices); /// @ingroup channels_setters /// @notdoced + /// @cpponly void setInlineSuperOp(SuperOp op, int numQb, std::vector> matrix); @@ -487,11 +489,13 @@ extern "C" { /// @ingroup channels_create /// @notdoced + /// @cpponly KrausMap createInlineKrausMap(int numQubits, int numOperators, std::vector>> matrices); /// @ingroup channels_create /// @notdoced + /// @cpponly SuperOp createInlineSuperOp(int numQubits, std::vector> matrix); From 3145ac83ca170400050c2d394511ef87f5866940 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 21:13:55 +0200 Subject: [PATCH 17/24] separated example and tutorials --- README.md | 2 +- docs/README.md | 2 +- docs/tutorial.md | 755 +++++++++++++++++++++++++++++++++++++++++++++ examples/README.md | 755 +-------------------------------------------- 4 files changed, 760 insertions(+), 754 deletions(-) create mode 100644 docs/tutorial.md diff --git a/README.md b/README.md index acdccad86..e581a58ca 100644 --- a/README.md +++ b/README.md @@ -185,7 +185,7 @@ QuEST supports: Visit the [docs](docs/README.md) to: - [see what's new in v4](docs/v4.md) - - [follow the tutorial](/examples/README.md#tutorial) + - [follow the tutorial](docs/tutorial.md) - [compile with cmake](docs/compile.md) - [find compatible compilers](docs/compilers.md) - [launch your simulations](docs/launch.md) diff --git a/docs/README.md b/docs/README.md index 2f9b7fc12..cc98e6706 100644 --- a/docs/README.md +++ b/docs/README.md @@ -22,7 +22,7 @@ To get started with QuEST, check out - 🛠️  [`compile.md`](compile.md) for instructions on compiling. - ⚙️  [`cmake.md`](cmake.md) for a list of compiler variables. - 🚀  [`launch.md`](launch.md) to learn how to run QuEST on laptops to supercomputers. -- 🎓  [`tutorial.md`](/examples/README.md#tutorial) for an introductory tutorial. +- 🎓  [`tutorial.md`](tutorial.md) for an introductory tutorial. - 📋  [API](https://quest-kit.github.io/QuEST/group__api.html) for the documentation of each function. Interested in contributing? Then check out: diff --git a/docs/tutorial.md b/docs/tutorial.md new file mode 100644 index 000000000..8241a19e6 --- /dev/null +++ b/docs/tutorial.md @@ -0,0 +1,755 @@ +# 🎓  Tutorial + + + +QuEST is included into a `C` or `C++` project via +```C++ +#include "quest.h" +``` + +> [!TIP] +> Some of QuEST's deprecated `v3` API can be accessed by specifying `ENABLE_DEPRECATED_API` when [compiling](/docs/compile.md#v3), or defining it before import, i.e. +> ```C++ +> #define ENABLE_DEPRECATED_API 1 +> #include "quest.h" +> ``` +> We recommend migrating to the latest `v4` API however as will be showcased below. + +Simulation typically proceeds as: +1. [Initialise](https://quest-kit.github.io/QuEST/group__environment.html#gab89cfc1bf94265f4503d504b02cf54d4) the QuEST [environment](https://quest-kit.github.io/QuEST/group__environment.html), preparing available GPUs and networks. +2. [Configure](https://quest-kit.github.io/QuEST/group__debug.html) the environment, such as through [seeding](https://quest-kit.github.io/QuEST/group__debug__seed.html). +3. [Create](https://quest-kit.github.io/QuEST/group__qureg__create.html) a [`Qureg`](https://quest-kit.github.io/QuEST/structQureg.html), allocating memory for its amplitudes. +4. Prepare its [initial state](https://quest-kit.github.io/QuEST/group__initialisations.html), overwriting its amplitudes. +5. Apply [operators](https://quest-kit.github.io/QuEST/group__operations.html) and [decoherence](https://quest-kit.github.io/QuEST/group__decoherence.html), expressed as [matrices](https://quest-kit.github.io/QuEST/group__matrices.html) and [channels](https://quest-kit.github.io/QuEST/group__channels.html). +6. Perform [calculations](https://quest-kit.github.io/QuEST/group__calculations.html), potentially using [Pauli](https://quest-kit.github.io/QuEST/group__paulis.html) observables. +7. [Report](https://quest-kit.github.io/QuEST/group__types.html) or log the results to file. +8. Destroy any heap-allocated [`Qureg`](https://quest-kit.github.io/QuEST/group__qureg__destroy.html) or [matrices](https://quest-kit.github.io/QuEST/group__matrices__destroy.html). +8. [Finalise](https://quest-kit.github.io/QuEST/group__environment.html#ga428faad4d68abab20f662273fff27e39) the QuEST environment. + +Of course, the procedure is limited only by the programmers imagination `¯\_(ツ)_/¯` Let's see an example of these steps below. + + +> **TOC**: +> - [1. Initialise the environment](#1-initialise-the-environment) +> - [2. Configure the environment](#2-configure-the-environment) +> - [3. Create a `Qureg`](#3-create-a--qureg-) +> - [4. Prepare an initial state](#4-prepare-an-initial-state) +> - [5. Apply operators](#5-apply-operators) +> * [controls](#controls) +> * [paulis](#paulis) +> * [matrices](#matrices) +> * [circuits](#circuits) +> * [measurements](#measurements) +> * [decoherence](#decoherence) +> - [6. Perform calculations](#6-perform-calculations) +> - [7. Report the results](#7-report-the-results) +> - [8. Cleanup](#8-cleanup) +> - [9. Finalise QuEST](#9-finalise-quest) + + + +## 1. Initialise the environment + +Before calling any other QuEST functions, we must [_initialise_](https://quest-kit.github.io/QuEST/group__environment.html#gab89cfc1bf94265f4503d504b02cf54d4) the QuEST [_environment_](https://quest-kit.github.io/QuEST/group__environment.html). +```C++ +initQuESTEnv(); +``` +This does several things, such as +- assessing which hardware accelerations (multithreading, GPU-acceleration, distribution, cuQuantum) were compiled and are currently available to use. +- initialising any external libraries as needed, like MPI, CUDA and cuQuantum. +- seeding the random number generators (informing measurements and random states), using a [CSPRNG](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator) if available. + +We could instead forcefully [disable](https://quest-kit.github.io/QuEST/group__environment.html#ga485268e52f838743357e7a4c8c241e57) certain hardware accelerations +```C++ +int useMPI = 0; +int useGPU = 0; +int useOMP = 0; +initCustomQuESTEnv(useMPI, useGPU, useOMP); +``` + +> [!TIP] +> We recommend enabling _all_ deployments, as automated by `initQuESTEnv()`, which +> permits QuEST to choose how to best accelerate subsequently created `Qureg`. + +We can [view](https://quest-kit.github.io/QuEST/group__environment.html#ga08bf98478c4bf21b0759fa7cd4a97496) the environment configuration at runtime, via +```C++ +reportQuESTEnv(); +``` +which might output something like +``` +QuEST execution environment: + [precision] + qreal.................double (8 bytes) + qcomp.................std::__1::complex (16 bytes) + qindex................long long int (8 bytes) + validationEpsilon.....1e-12 + [compilation] + isMpiCompiled...........1 + isGpuCompiled...........1 + isOmpCompiled...........1 + isCuQuantumCompiled.....0 + [deployment] + isMpiEnabled.....0 + isGpuEnabled.....1 + isOmpEnabled.....1 + [cpu] + numCpuCores.......10 per machine + numOmpProcs.......10 per machine + numOmpThrds.......8 per node + cpuMemory.........32 GiB per node + cpuMemoryFree.....7.1 GiB per node + [gpu] + numGpus...........1 + gpuDirect.........1 + gpuMemPools.......1 + gpuMemory.........15.9 GiB per node + gpuMemoryFree.....15.2 GiB per node + gpuCache..........1 GiB + [distribution] + isMpiGpuAware.....0 + numMpiNodes.......8 + [statevector limits] + minQubitsForMpi.............3 + maxQubitsForCpu.............30 + maxQubitsForGpu.............29 + maxQubitsForMpiCpu..........35 + maxQubitsForMpiGpu..........34 + maxQubitsForMemOverflow.....59 + maxQubitsForIndOverflow.....63 + [density matrix limits] + minQubitsForMpi.............2 + maxQubitsForCpu.............15 + maxQubitsForGpu.............14 + maxQubitsForMpiCpu..........17 + maxQubitsForMpiGpu..........16 + maxQubitsForMemOverflow.....29 + maxQubitsForIndOverflow.....31 + [statevector autodeployment] + 8 qubits.....[omp] + 12 qubits....[gpu] + 29 qubits....[gpu] [mpi] + [density matrix autodeployment] + 4 qubits.....[omp] + 6 qubits.....[gpu] + 15 qubits....[gpu] [mpi] +``` + +We can also [obtain](https://quest-kit.github.io/QuEST/group__environment.html#ga6b9e84b462a999a1fbb9a372f990c491) some of the environment information [programmatically](https://quest-kit.github.io/QuEST/structQuESTEnv.html) +```C++ +QuESTEnv env = getQuESTEnv(); + +if (env.isGpuAccelerated) + printf("vroom vroom"); +``` + + +## 2. Configure the environment + +Configuring the environment is ordinarily not necessary, but convenient in certain applications. + +For example, we may wish our simulations to deterministically obtain the same measurement outcomes and random states as a previous or future run, and ergo choose to [override](https://quest-kit.github.io/QuEST/group__debug__seed.html#ga9e3a6de413901afbf50690573add1587) the default seeds. +```C++ +unsigned seeds[] = {123u, 1u << 10}; +setSeeds(seeds, 2); +``` + +We may wish further to [adjust](https://quest-kit.github.io/QuEST/group__debug__reporting.html) how subsequent functions will display information to the screen +```C++ +int maxRows = 8; +int maxCols = 4; +setMaxNumReportedItems(maxRows, maxCols); +setMaxNumReportedSigFigs(3); +``` +or [add](https://quest-kit.github.io/QuEST/group__debug__reporting.html#ga29413703d609254244d6b13c663e6e06) extra spacing between QuEST's printed outputs +```C++ +setNumReportedNewlines(3); +``` + +Perhaps we also wish to relax the [precision](https://quest-kit.github.io/QuEST/group__debug__validation.html#gae395568df6def76045ec1881fcb4e6d1) with which our future inputs will be asserted unitary or Hermitian +```C++ +setValidationEpsilon(0.001); +``` +but when unitarity _is_ violated, or we otherwise pass an invalid input, we wish to execute a [custom function](https://quest-kit.github.io/QuEST/group__debug__validation.html#ga14b6e7ce08465e36750da3acbc41062f) before exiting. +```C++ +#include + +void myErrorHandler(const char *func, const char *msg) { + printf("QuEST function '%s' encountered error '%s'\n", func, msg); + printf("Exiting...\n"); + exit(1); +} + +setInputErrorHandler(myErrorHandler); +``` + +> [!TIP] +> `C++` users may prefer to throw an exception which can be caught, safely permitting execution to continue. In such cases, the erroneous function will _never_ corrupt any passed inputs like `Qureg` nor matrices, nor cause leaks. +> ```C++ +> #include +> #include +> +> void myErrorHandlerA(const char* errFunc, const char* errMsg) { +> std::string func(errFunc); +> std::string msg(errMsg); +> throw std::runtime_error(func + ": " + msg); +> } +> +> setInputErrorHandler(myErrorHandler); +> ``` + +## 3. Create a `Qureg` + +To [create](https://quest-kit.github.io/QuEST/group__qureg__create.html) a statevector of `10` qubits, we call +```C++ +Qureg qureg = createQureg(10); +``` +which we can [verify](https://quest-kit.github.io/QuEST/group__qureg__report.html#ga2a9df2538e537332b1aef8596ce337b2) has begun in the very boring zero state. +```C++ +reportQureg(qureg); +``` +``` +Qureg (10 qubit statevector, 1024 qcomps, 16.1 KiB): + 1 |0⟩ + 0 |1⟩ + 0 |2⟩ + 0 |3⟩ + ⋮ + 0 |1020⟩ + 0 |1021⟩ + 0 |1022⟩ + 0 |1023⟩ +``` +> This printed only `8` amplitudes as per our setting of [`setMaxNumReportedItems()`](https://quest-kit.github.io/QuEST/group__debug__reporting.html#ga093c985b1970a0fd8616c01b9825979a) above. + +Behind the scenes, the function `createQureg` did something clever; it consulted the compiled deployments and available hardware to decide whether to distribute `qureg`, or dedicate it persistent GPU memory, and marked whether or not to multithread its subsequent modification. It attempts to choose _optimally_, avoiding gratuitous parallelisation if the overheads outweigh the benefits, or if the hardware devices have insufficient memory. + +We call this **_auto-deployment_**, and the chosen configuration can be [previewed](https://quest-kit.github.io/QuEST/group__qureg__report.html#ga97d96af7c7ea7b31e32cbe3b25377e09) via +```C++ +reportQuregParams(qureg); +``` +``` +Qureg: + [deployment] + isMpiEnabled.....0 + isGpuEnabled.....0 + isOmpEnabled.....1 + [dimension] + isDensMatr.....0 + numQubits......10 + numCols........N/A + numAmps........2^10 = 1024 + [distribution] + numNodes.....N/A + numCols......N/A + numAmps......N/A + [memory] + cpuAmps...........16 KiB + gpuAmps...........N/A + cpuCommBuffer.....N/A + gpuCommBuffer.....N/A + globalTotal.......16 KiB +``` +The above output informs us that the `qureg` has not been distributed nor GPU-accelerated, but _will_ be multithreaded. + +If we so wished, we could [_force_](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga619bbba1cbc2f7f9bbf3d3b86b3f02be) the use of all deployments available to the environment +```C++ +Qureg qureg = createForcedQureg(10); +reportQuregParams(qureg); +``` +``` +Qureg: + [deployment] + isMpiEnabled.....1 + isGpuEnabled.....1 + isOmpEnabled.....1 + [dimension] + isDensMatr.....0 + numQubits......10 + numCols........N/A + numAmps........2^10 = 1024 + [distribution] + numNodes.....2^3 = 8 + numCols......N/A + numAmps......2^7 = 128 per node + [memory] + cpuAmps...........2 KiB per node + gpuAmps...........2 KiB per node + cpuCommBuffer.....2 KiB per node + gpuCommBuffer.....2 KiB per node + globalTotal.......64 KiB +``` +or [select](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga849971f43e246d103da1731d0901f2e6) specific deployments +```C++ +int useMPI = 1; +int useGPU = 0; +int useOMP = 0; +Qureg qureg = createCustomQureg(10, 0, useMPI, useGPU, useOMP); +``` + +In lieu of a statevector, we could create a [density matrix](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga1470424b0836ae18b5baab210aedf5d9) +```C++ +Qureg qureg = createDensityQureg(10); +``` +which is also auto-deployed. Note this contains _square_ as many amplitudes as the equal-dimension statevector and ergo requires _square_ as much memory. +```C++ +reportQureg(qureg); +reportQuregParams(qureg); +``` +``` +Qureg (10 qubit density matrix, 1024x1024 qcomps, 16 MiB): + 1 0 … 0 0 + 0 0 … 0 0 + 0 0 … 0 0 + 0 0 … 0 0 + ⋮ + 0 0 … 0 0 + 0 0 … 0 0 + 0 0 … 0 0 + 0 0 … 0 0 + + +Qureg: + ... + [dimension] + isDensMatr.....1 + numQubits......10 + numCols........2^10 = 1024 + numAmps........2^20 = 1048576 + ... + [memory] + cpuAmps...........16 MiB + ... + globalTotal.......16 MiB +``` + +> The spacing between the outputs of those two consecutive QuEST functions was determined by our earlier call to [`setMaxNumReportedSigFigs()`](https://quest-kit.github.io/QuEST/group__debug__reporting.html#ga29413703d609254244d6b13c663e6e06). + + +A density matrix `Qureg` can model classical uncertainty as results from [decoherence](https://quest-kit.github.io/QuEST/group__decoherence.html), and proves useful when simulating quantum operations on a noisy quantum computer. + + +## 4. Prepare an initial state + +In lieu of manually [modifying](https://quest-kit.github.io/QuEST/group__init__amps.html) the state amplitudes, QuEST includes functions to prepare a `Qureg` in some common [initial states](https://quest-kit.github.io/QuEST/group__init__states.html) + +```C++ +initZeroState(qureg); // |0> or |0><0| +initPlusState(qureg); // |+> or |+><+| +initClassicalState(qureg, i); // |i> or |i> The number of printed significant figures above results from our earlier calling of [`setMaxNumReportedSigFigs()`](https://quest-kit.github.io/QuEST/group__debug__reporting.html#ga15d46e5d813f70b587762814964e1994). + + +## 5. Apply operators + +QuEST supports an extensive set of [operators](https://quest-kit.github.io/QuEST/group__operations.html) to effect upon a `Qureg`. +```C++ +int target = 2; +applyHadamard(qureg, target); + +qreal angle = 3.14 / 5; +int targets[] = {4,5,6}; +applyPhaseGadget(qureg, targets, 3, angle); +``` + +> [!IMPORTANT] +> Notice the type of `angle` is [`qreal`](https://quest-kit.github.io/QuEST/group__types.html#ga2d479c159621c76ca6f96abe66f2e69e) rather than the expected `double`. This is a precision agnostic alias for a floating-point, real scalar which allows you to recompile QuEST with a varying [precision](/docs/compile.md#precision) with no modifications to your code. + +### controls + +All unitary operations accept any number of control qubits +```C++ +int controls[] = {0,1,2,3,7,8,9}; +applyMultiControlledSqrtSwap(qureg, controls, 7, targets[0], targets[1]); +``` +and even _control states_ which specify the bits (`0` or `1`) that the respective controls must be in to effect the non-identity operation. +```C++ +int states[] = {0,0,0,1,1,1,0}; +applyMultiStateControlledRotateX(qureg, controls, states, 7, target, angle); +``` + +> [!TIP] +> `C` users can pass inline list arguments using [compound literals](https://en.cppreference.com/w/c/language/compound_literal) +> ```C +> applyMultiControlledMultiQubitNot(qureg, (int[]) {0,1,2}, 3, (int[]) {4,5}, 2); +> ``` +> while `C++` users can pass [vector](https://en.cppreference.com/w/cpp/container/vector) literals or [initializer lists](https://en.cppreference.com/w/cpp/utility/initializer_list), alleviating the need to specify the list lengths. +> ```C++ +> applyMultiControlledMultiQubitNot(qureg, {0,1,2}, {4,5}); +> ``` + +### paulis + +Some operators accept [`PauliStr`](https://quest-kit.github.io/QuEST/structPauliStr.html) which can be [constructed](https://quest-kit.github.io/QuEST/group__paulis__create.html) all sorts of ways - even inline! +```C++ +applyPauliGadget(qureg, getPauliStr("XYZ"), angle); +``` + +> [!TIP] +> Using _one_ QuEST function is _always_ faster than using an equivalent sequence. So +> ```C++ +> applyPauliStr(qureg, getPauliStr("YYYYYYY")); +> ``` +> is _much_ faster than +> ```C++ +> for (int i=0; i<7; i++) +> applyPauliY(qureg, i); +> ``` + +### matrices + +#### `CompMatr1` + +Don't see your operation in the API? You can specify it as a general [matrix](https://quest-kit.github.io/QuEST/group__matrices.html). +```C++ +qcomp x = 1i/sqrt(2); +CompMatr1 matrix = getInlineCompMatr({{-x,x},{-x,-x}}); +applyCompMatr1(qureg, target, matrix); +``` + +> [!IMPORTANT] +> The type [`qcomp`](https://quest-kit.github.io/QuEST/group__types.html#ga4971f489e74bb185b9b2672c14301983) above is a precision agnostic complex scalar, and has beautiful arithmetic overloads! +> ```C++ +> qcomp x = 1.5 + 3.14i; +> qcomp *= 1E3i - 1E-5i; +> ``` +> Beware that in `C++`, `1i` is a _double precision_ literal, so `C++` users should instead +> use the custom precision-agnostic literal `1_i`. +> ```C++ +> qcomp x = 1.5 + 3.14_i; +> ``` + +#### `CompMatr` + +Want a bigger matrix? No problem - they can be [any size](https://quest-kit.github.io/QuEST/group__matrices__create.html#ga634309472d1edf400174680af0685b89), with many ways to [initialise](https://quest-kit.github.io/QuEST/group__matrices__setters.html) them. +```C++ +CompMatr bigmatrix = createCompMatr(8); +setCompMatr(bigmatrix, {{1,2,3,...}}); +applyCompMatr(qureg, ..., bigmatrix); +``` +Matrix elements can be manually modified, though this requires we [synchronise](https://quest-kit.github.io/QuEST/group__matrices__sync.html) them with GPU memory once finished. +```C++ +qindex dim = bigmatrix.numRows; + +// initialise random diagonal unitary +for (qindex r=0; r [!IMPORTANT] +> The created `CompMatr` is a [heap object](https://craftofcoding.wordpress.com/2015/12/07/memory-in-c-the-stack-the-heap-and-static/) and must be [destroyed](https://quest-kit.github.io/QuEST/group__matrices__destroy.html) when we are finished with it, to free up its memory and avoid leaks. +> ```C++ +> destroyCompMatr(bigmatrix); +> ``` +> This is true of any QuEST structure returned by a `create*()` function. It is _not_ true of functions prefixed with `get*()` with are always [stack variables](https://craftofcoding.wordpress.com/2015/12/07/memory-in-c-the-stack-the-heap-and-static/), hence why functions like `getCompMatr1()` can be called inline! + + +#### `FullStateDiagMatr` + +Above, we initialised [`CompMatr`](https://quest-kit.github.io/QuEST/structCompMatr.html) to a diagonal unitary. This is incredibly wasteful; only `256` of its `65536` elements are non-zero! We should instead use [`DiagMatr`](https://quest-kit.github.io/QuEST/structDiagMatr.html) or [`FullStateDiagMatr`](https://quest-kit.github.io/QuEST/structFullStateDiagMatr.html). The latter is even distributed (if chosen by the autodeployer), permitting it to be as large as a `Qureg` itself! +```C++ +FullStateDiagMatr fullmatrix = createFullStateDiagMatr(qureg.numQubits); +``` +and can be [initialised](https://quest-kit.github.io/QuEST/group__matrices__setters.html) in many ways, including from all-`Z` pauli sums! +```C++ +PauliStrSum sum = createInlinePauliStrSum(R"( + 1 II + 1i ZI + 1i IZ + -1 ZZ +)"); + +setFullStateDiagMatrFromPauliStrSum(fullmatrix, sum); +``` +> [!IMPORTANT] +> The argument to `createInlinePauliStrSum` is a multiline string for which the syntax differs between `C` and `C++`; we used the latter above. See examples [`initialisation.c`](/examples/paulis/initialisation.c) and [`initialisation.cpp`](/paulis/matrices/initialisation.cpp) for clarity. + +> [!CAUTION] +> Beware that in distributed settings, because `fullmatrix` _may_ be distributed, we should must exercise extreme caution when modifying its `fullmatrix.cpuElems` directly. + + +A `FullStateDiagMatr` acts upon all qubits of a qureg +```C++ +applyFullStateDiagMatr(qureg, fullmatrix); +``` +and can be raised to an arbitrary power, helpful for example in simulating [quantum spectral methods](https://www.science.org/doi/10.1126/sciadv.abo7484). +```C++ +qcomp exponent = 3.5; +applyFullStateDiagMatrPower(qureg, fullmatrix, exponent); +``` + +Notice the `exponent` is a `qcomp` and ergo permitted to be a complex number. Unitarity requires `exponent` is strictly real, but we can always relax the unitarity validation... + + +#### validation + + +Our example above initialised `CompMatr` to a diagonal because it is tricky to generate random non-diagonal **_unitary_** matrices - and QuEST checks for unitarity! +```C++ +// m * dagger(m) != identity +CompMatr1 m = getCompMatr1({{.1,.2},{.3,.4}}); +applyCompMatr1(qureg, 0, m); +``` +``` +QuEST encountered a validation error during function 'applyCompMatr1': +The given matrix was not (approximately) unitary. +Exiting... +``` +If we're satisfied our matrix _is_ sufficiently approximately unitary, we can [adjust](https://quest-kit.github.io/QuEST/group__debug__validation.html#gae395568df6def76045ec1881fcb4e6d1) or [disable](https://quest-kit.github.io/QuEST/group__debug__validation.html#ga5999824df0785ea88fb2d5b5582f2b46) the validation. +```C++ +// max(norm(m * dagger(m) - identity)) = 0.9025 +setValidationEpsilon(0.903); +applyCompMatr1(qureg, 0, m); +``` + + +### circuits + +QuEST includes a few convenience functions for effecting [QFT](https://quest-kit.github.io/QuEST/group__op__qft.html) and [Trotter](https://quest-kit.github.io/QuEST/group__op__paulistrsum.html) circuits. + +```C++ +applyQuantumFourierTransform(qureg, targets, 3); + +qreal time = .3; +int order = 4; +int reps = 10; +applyTrotterizedPauliStrSumGadget(qureg, sum, time, order, reps); +``` + + + +### measurements + +We can also effect a wide range of non-unitary operations, such as destructive [measurements](https://quest-kit.github.io/QuEST/group__op__measurement.html) +```C++ +int outcome1 = applyQubitMeasurement(qureg, 0); + +qreal prob; +qindex outcome2 = applyMultiQubitMeasurementAndGetProb(qureg, targets, 3, &prob); +``` +and conveniently [report](https://quest-kit.github.io/QuEST/group__types.html#ga2be8a4433585a8d737c02128b4754a03) their outcome. +```C++ +reportScalar("one qubit outcome", outcome1); +reportScalar("three qubit outcome", outcome2); +``` + +> [!IMPORTANT] +> Notice the type of `outcome2` is a [`qindex`](https://quest-kit.github.io/QuEST/group__types.html#ga6017090d3ed4063ee7233e20c213424b) rather than an `int`. This is a larger type which can store much larger numbers without overflow - up to `2^63` - and is always used by the API for many-qubit indices. + +Should we wish to leave the state unnormalised, we can instead use [projectors](https://quest-kit.github.io/QuEST/group__op__projectors.html). + +### decoherence + +Density matrices created with [`createDensityQureg()`](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga1470424b0836ae18b5baab210aedf5d9) can undergo [decoherence](https://quest-kit.github.io/QuEST/group__decoherence.html) channels. + +```C++ +qreal prob = 0.1; +mixDamping(rho, target, prob); +mixDephasing(rho, target, prob); +mixTwoQubitDepolarising(rho, targets[0], targets[1], prob); +``` +which we can specify as inhomogeneous Pauli channels +```C++ +// passing probabilities of X, Y, Z errors respectively +mixPaulis(Qureg qureg, target, .05, .10, .15); +``` +or completely generally as [Kraus maps](https://quest-kit.github.io/QuEST/group__channels.html) and [superoperators](https://quest-kit.github.io/QuEST/group__channels.html)! +```C++ +int numTargets = 1; +int numOperators = 4; + +qreal p = 0.1; +qreal l = 0.3; + +// generalised amplitude damping +KrausMap map = createInlineKrausMap(numTargets, numOperators, { + { + {sqrt(p), 0}, + {0, sqrt(p*(1-l))} + }, { + {0, sqrt(p*l)}, + {0, 0} + }, { + {sqrt((1-p)*(1-l)), 0}, + {0, sqrt(1-p)} + }, { + {0, 0}, + {sqrt((1-p)*l), 0} + } +}); + +int victims[] = {2}; +mixKrausMap(rho, victims, 1, map); +``` +We can even directy mix density matrices together +```C++ +mixQureg(rho1, rho2, prob); +``` + +Sometimes we wish to left-multiply general operators upon density matrices without also right-multiplying their adjoint - i.e. our operators should _not_ be effected as unitaries. We can do this with the `multiply*()` functions. +```C++ +multiplyDiagMatrPower(rho, fullmatrix, 0.5); +``` + + +## 6. Perform calculations + +After so much modification to our state, we will find that its amplitudes have differed substantially. But it's impractical to observe the exponentially-many amplitudes with [`reportQureg()`](https://quest-kit.github.io/QuEST/group__qureg__report.html#ga2a9df2538e537332b1aef8596ce337b2). We can instead give QuEST the [questions](https://quest-kit.github.io/QuEST/group__calculations.html) we wish to answer about the resulting state. + +For example, we can find the [probability](https://quest-kit.github.io/QuEST/group__calc__prob.html) of measurement outcomes _without_ modifying the state. +```C++ +int outcome = 1; +qreal prob1 = calcProbOfQubitOutcome(qureg, target, outcome); + +int qubits[] = {2,3,4}; +int outcomes[] = {0,1,1}; +qreal prob2 = calcProbOfMultiQubitOutcome(qureg, qubits, outcomes, 3); +``` +We can obtain _all_ outcome probabilities in one swoop: +```C++ +qreal probs[8]; +calcProbsOfAllMultiQubitOutcomes(probs, qureg, qubits, 3); +``` + +> [!TIP] +> `C++` users can also obtain the result as a natural `std::vector`. +> ```C++ +> auto probs = calcProbsOfAllMultiQubitOutcomes(qureg, {2,3,4}); +> ``` + +It is similarly trivial to find [expectation values](https://quest-kit.github.io/QuEST/group__calc__expec.html) +```C++ +qreal expec1 = calcExpecPauliStr(qureg, getPauliStr("XYZIII")); +qreal expec2 = calcExpecPauliStrSum(qureg, sum); +qreal expec3 = calcExpecFullStateDiagMatr(qureg, fullmatrix); +``` +or [distance measures](https://quest-kit.github.io/QuEST/group__calc__comparisons.html) between states, including between statevectors and density matrices. +```C++ +qreal pur = calcPurity(rho); +qreal fid = calcFidelity(rho, psi); +qreal dist = calcDistance(rho, psi); +``` + +We can even find reduced density matrices resulting from [partially tracing](https://quest-kit.github.io/QuEST/group__calc__partialtrace.html) out qubits. +```C++ +Qureg reduced = calcPartialTrace(qureg, targets, 3); + +reportScalar("entanglement", calcPurity(reduced)); +``` + +## 7. Report the results + +We've seen above that [scalars](https://quest-kit.github.io/QuEST/group__types.html) can be reported, handling the pretty formatting of real and complex numbers, controlled by settings like [`setMaxNumReportedSigFigs()`](https://quest-kit.github.io/QuEST/group__debug__reporting.html#ga15d46e5d813f70b587762814964e1994). But we can also report every data structure in the QuEST API, such as Pauli strings +```C++ +reportPauliStr( + getInlinePauliStr("XXYYZZ", {5,50, 10,60, 30,40}) +); +``` +``` +YIIIIIIIIIXIIIIIIIIIZIIIIIIIIIZIIIIIIIIIIIIIIIIIIIYIIIIXIIIII +``` +and their weighted sums +```C++ +reportPauliStrSum(sum); +``` +``` +PauliStrSum (4 terms, 160 bytes): + 1 II + i ZI + i IZ + -1 ZZ +``` +All outputs are affected by the [reporter settings](https://quest-kit.github.io/QuEST/group__debug__reporting.html). +```C++ +setMaxNumReportedItems(4,4); +setMaxNumReportedSigFigs(1); +reportCompMatr(bigmatrix); +``` +``` +CompMatr (8 qubits, 256x256 qcomps, 1 MiB): + 0.9-0.5i 0 … 0 0 + 0 0.8-0.6i … 0 0 + ⋮ + 0 0 … -0.5-0.9i 0 + 0 0 … 0 0.4+0.9i +``` + + + +> [!NOTE] +> Facilities for automatically logging to file are coming soon! + + +## 8. Cleanup + +While not strictly necessary before the program ends, it is a good habit to destroy data structures as soon as you are finished with them, freeing their memory. + +```C++ +destroyQureg(qureg); +destroyCompMatr(bigmatrix); +destroyFullStateDiagMatr(fullmatrix); +destroyPauliStrSum(sum); +destroyKrausMap(map); +``` + +## 9. Finalise QuEST + +The **_final_** [step](https://quest-kit.github.io/QuEST/group__environment.html#ga428faad4d68abab20f662273fff27e39) of our program should be to call +```C++ +finalizeQuESTEnv(); +``` +which ensures everything is synchronised, frees accelerator resources, and finalises MPI. +This is important because it ensures: +- _everything is done_, and that distributed nodes that are still working (e.g. haven't yet logged to their own file) are not interrupted by early termination of another node. +- the MPI process ends gracefully, and doesn't spew out messy errors! +- our GPU processes are killed quickly, freeing resources for other processes. + +> [!CAUTION] +> After calling `finalizeQuESTEnv()`, MPI will close and each if being accessed directly by the user, will enter an undefined state. Subsequent calls to MPI routines may return gibberish, and distributed machines will have lost their ability to communicate. It is recommended to call `finalizeQuESTEnv()` immediately before exiting. + +You are now a QuEST expert 🎉 though there are _many_ more functions in the [API](https://quest-kit.github.io/QuEST/group__api.html) not covered here. Go forth and simulate! \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index 0aa200790..08e536881 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,759 +1,10 @@ +# 🔖  Examples + -# 🔖  Examples - 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. - - -# 🎓  Tutorial - -QuEST is included into a `C` or `C++` project via -```C++ -#include "quest.h" -``` - -> [!TIP] -> Some of QuEST's deprecated `v3` API can be accessed by specifying `ENABLE_DEPRECATED_API` when [compiling](/docs/compile.md#v3), or defining it before import, i.e. -> ```C++ -> #define ENABLE_DEPRECATED_API 1 -> #include "quest.h" -> ``` -> We recommend migrating to the latest `v4` API however as will be showcased below. - -Simulation typically proceeds as: -1. [Initialise](https://quest-kit.github.io/QuEST/group__environment.html#gab89cfc1bf94265f4503d504b02cf54d4) the QuEST [environment](https://quest-kit.github.io/QuEST/group__environment.html), preparing available GPUs and networks. -2. [Configure](https://quest-kit.github.io/QuEST/group__debug.html) the environment, such as through [seeding](https://quest-kit.github.io/QuEST/group__debug__seed.html). -3. [Create](https://quest-kit.github.io/QuEST/group__qureg__create.html) a [`Qureg`](https://quest-kit.github.io/QuEST/structQureg.html), allocating memory for its amplitudes. -4. Prepare its [initial state](https://quest-kit.github.io/QuEST/group__initialisations.html), overwriting its amplitudes. -5. Apply [operators](https://quest-kit.github.io/QuEST/group__operations.html) and [decoherence](https://quest-kit.github.io/QuEST/group__decoherence.html), expressed as [matrices](https://quest-kit.github.io/QuEST/group__matrices.html) and [channels](https://quest-kit.github.io/QuEST/group__channels.html). -6. Perform [calculations](https://quest-kit.github.io/QuEST/group__calculations.html), potentially using [Pauli](https://quest-kit.github.io/QuEST/group__paulis.html) observables. -7. [Report](https://quest-kit.github.io/QuEST/group__types.html) or log the results to file. -8. Destroy any heap-allocated [`Qureg`](https://quest-kit.github.io/QuEST/group__qureg__destroy.html) or [matrices](https://quest-kit.github.io/QuEST/group__matrices__destroy.html). -8. [Finalise](https://quest-kit.github.io/QuEST/group__environment.html#ga428faad4d68abab20f662273fff27e39) the QuEST environment. - -Of course, the procedure is limited only by the programmers imagination `¯\_(ツ)_/¯` Let's see an example of these steps below. - - -> **TOC**: -> - [1. Initialise the environment](#1-initialise-the-environment) -> - [2. Configure the environment](#2-configure-the-environment) -> - [3. Create a `Qureg`](#3-create-a--qureg-) -> - [4. Prepare an initial state](#4-prepare-an-initial-state) -> - [5. Apply operators](#5-apply-operators) -> * [controls](#controls) -> * [paulis](#paulis) -> * [matrices](#matrices) -> * [circuits](#circuits) -> * [measurements](#measurements) -> * [decoherence](#decoherence) -> - [6. Perform calculations](#6-perform-calculations) -> - [7. Report the results](#7-report-the-results) -> - [8. Cleanup](#8-cleanup) -> - [9. Finalise QuEST](#9-finalise-quest) - - - -## 1. Initialise the environment - -Before calling any other QuEST functions, we must [_initialise_](https://quest-kit.github.io/QuEST/group__environment.html#gab89cfc1bf94265f4503d504b02cf54d4) the QuEST [_environment_](https://quest-kit.github.io/QuEST/group__environment.html). -```C++ -initQuESTEnv(); -``` -This does several things, such as -- assessing which hardware accelerations (multithreading, GPU-acceleration, distribution, cuQuantum) were compiled and are currently available to use. -- initialising any external libraries as needed, like MPI, CUDA and cuQuantum. -- seeding the random number generators (informing measurements and random states), using a [CSPRNG](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator) if available. - -We could instead forcefully [disable](https://quest-kit.github.io/QuEST/group__environment.html#ga485268e52f838743357e7a4c8c241e57) certain hardware accelerations -```C++ -int useMPI = 0; -int useGPU = 0; -int useOMP = 0; -initCustomQuESTEnv(useMPI, useGPU, useOMP); -``` - -> [!TIP] -> We recommend enabling _all_ deployments, as automated by `initQuESTEnv()`, which -> permits QuEST to choose how to best accelerate subsequently created `Qureg`. - -We can [view](https://quest-kit.github.io/QuEST/group__environment.html#ga08bf98478c4bf21b0759fa7cd4a97496) the environment configuration at runtime, via -```C++ -reportQuESTEnv(); -``` -which might output something like -``` -QuEST execution environment: - [precision] - qreal.................double (8 bytes) - qcomp.................std::__1::complex (16 bytes) - qindex................long long int (8 bytes) - validationEpsilon.....1e-12 - [compilation] - isMpiCompiled...........1 - isGpuCompiled...........1 - isOmpCompiled...........1 - isCuQuantumCompiled.....0 - [deployment] - isMpiEnabled.....0 - isGpuEnabled.....1 - isOmpEnabled.....1 - [cpu] - numCpuCores.......10 per machine - numOmpProcs.......10 per machine - numOmpThrds.......8 per node - cpuMemory.........32 GiB per node - cpuMemoryFree.....7.1 GiB per node - [gpu] - numGpus...........1 - gpuDirect.........1 - gpuMemPools.......1 - gpuMemory.........15.9 GiB per node - gpuMemoryFree.....15.2 GiB per node - gpuCache..........1 GiB - [distribution] - isMpiGpuAware.....0 - numMpiNodes.......8 - [statevector limits] - minQubitsForMpi.............3 - maxQubitsForCpu.............30 - maxQubitsForGpu.............29 - maxQubitsForMpiCpu..........35 - maxQubitsForMpiGpu..........34 - maxQubitsForMemOverflow.....59 - maxQubitsForIndOverflow.....63 - [density matrix limits] - minQubitsForMpi.............2 - maxQubitsForCpu.............15 - maxQubitsForGpu.............14 - maxQubitsForMpiCpu..........17 - maxQubitsForMpiGpu..........16 - maxQubitsForMemOverflow.....29 - maxQubitsForIndOverflow.....31 - [statevector autodeployment] - 8 qubits.....[omp] - 12 qubits....[gpu] - 29 qubits....[gpu] [mpi] - [density matrix autodeployment] - 4 qubits.....[omp] - 6 qubits.....[gpu] - 15 qubits....[gpu] [mpi] -``` - -We can also [obtain](https://quest-kit.github.io/QuEST/group__environment.html#ga6b9e84b462a999a1fbb9a372f990c491) some of the environment information [programmatically](https://quest-kit.github.io/QuEST/structQuESTEnv.html) -```C++ -QuESTEnv env = getQuESTEnv(); - -if (env.isGpuAccelerated) - printf("vroom vroom"); -``` - - -## 2. Configure the environment - -Configuring the environment is ordinarily not necessary, but convenient in certain applications. - -For example, we may wish our simulations to deterministically obtain the same measurement outcomes and random states as a previous or future run, and ergo choose to [override](https://quest-kit.github.io/QuEST/group__debug__seed.html#ga9e3a6de413901afbf50690573add1587) the default seeds. -```C++ -unsigned seeds[] = {123u, 1u << 10}; -setSeeds(seeds, 2); -``` - -We may wish further to [adjust](https://quest-kit.github.io/QuEST/group__debug__reporting.html) how subsequent functions will display information to the screen -```C++ -int maxRows = 8; -int maxCols = 4; -setMaxNumReportedItems(maxRows, maxCols); -setMaxNumReportedSigFigs(3); -``` -or [add](https://quest-kit.github.io/QuEST/group__debug__reporting.html#ga29413703d609254244d6b13c663e6e06) extra spacing between QuEST's printed outputs -```C++ -setNumReportedNewlines(3); -``` - -Perhaps we also wish to relax the [precision](https://quest-kit.github.io/QuEST/group__debug__validation.html#gae395568df6def76045ec1881fcb4e6d1) with which our future inputs will be asserted unitary or Hermitian -```C++ -setValidationEpsilon(0.001); -``` -but when unitarity _is_ violated, or we otherwise pass an invalid input, we wish to execute a [custom function](https://quest-kit.github.io/QuEST/group__debug__validation.html#ga14b6e7ce08465e36750da3acbc41062f) before exiting. -```C++ -#include - -void myErrorHandler(const char *func, const char *msg) { - printf("QuEST function '%s' encountered error '%s'\n", func, msg); - printf("Exiting...\n"); - exit(1); -} - -setInputErrorHandler(myErrorHandler); -``` - -> [!TIP] -> `C++` users may prefer to throw an exception which can be caught, safely permitting execution to continue. In such cases, the erroneous function will _never_ corrupt any passed inputs like `Qureg` nor matrices, nor cause leaks. -> ```C++ -> #include -> #include -> -> void myErrorHandlerA(const char* errFunc, const char* errMsg) { -> std::string func(errFunc); -> std::string msg(errMsg); -> throw std::runtime_error(func + ": " + msg); -> } -> -> setInputErrorHandler(myErrorHandler); -> ``` - -## 3. Create a `Qureg` - -To [create](https://quest-kit.github.io/QuEST/group__qureg__create.html) a statevector of `10` qubits, we call -```C++ -Qureg qureg = createQureg(10); -``` -which we can [verify](https://quest-kit.github.io/QuEST/group__qureg__report.html#ga2a9df2538e537332b1aef8596ce337b2) has begun in the very boring zero state. -```C++ -reportQureg(qureg); -``` -``` -Qureg (10 qubit statevector, 1024 qcomps, 16.1 KiB): - 1 |0⟩ - 0 |1⟩ - 0 |2⟩ - 0 |3⟩ - ⋮ - 0 |1020⟩ - 0 |1021⟩ - 0 |1022⟩ - 0 |1023⟩ -``` -> This printed only `8` amplitudes as per our setting of [`setMaxNumReportedItems()`](https://quest-kit.github.io/QuEST/group__debug__reporting.html#ga093c985b1970a0fd8616c01b9825979a) above. - -Behind the scenes, the function `createQureg` did something clever; it consulted the compiled deployments and available hardware to decide whether to distribute `qureg`, or dedicate it persistent GPU memory, and marked whether or not to multithread its subsequent modification. It attempts to choose _optimally_, avoiding gratuitous parallelisation if the overheads outweigh the benefits, or if the hardware devices have insufficient memory. - -We call this **_auto-deployment_**, and the chosen configuration can be [previewed](https://quest-kit.github.io/QuEST/group__qureg__report.html#ga97d96af7c7ea7b31e32cbe3b25377e09) via -```C++ -reportQuregParams(qureg); -``` -``` -Qureg: - [deployment] - isMpiEnabled.....0 - isGpuEnabled.....0 - isOmpEnabled.....1 - [dimension] - isDensMatr.....0 - numQubits......10 - numCols........N/A - numAmps........2^10 = 1024 - [distribution] - numNodes.....N/A - numCols......N/A - numAmps......N/A - [memory] - cpuAmps...........16 KiB - gpuAmps...........N/A - cpuCommBuffer.....N/A - gpuCommBuffer.....N/A - globalTotal.......16 KiB -``` -The above output informs us that the `qureg` has not been distributed nor GPU-accelerated, but _will_ be multithreaded. - -If we so wished, we could [_force_](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga619bbba1cbc2f7f9bbf3d3b86b3f02be) the use of all deployments available to the environment -```C++ -Qureg qureg = createForcedQureg(10); -reportQuregParams(qureg); -``` -``` -Qureg: - [deployment] - isMpiEnabled.....1 - isGpuEnabled.....1 - isOmpEnabled.....1 - [dimension] - isDensMatr.....0 - numQubits......10 - numCols........N/A - numAmps........2^10 = 1024 - [distribution] - numNodes.....2^3 = 8 - numCols......N/A - numAmps......2^7 = 128 per node - [memory] - cpuAmps...........2 KiB per node - gpuAmps...........2 KiB per node - cpuCommBuffer.....2 KiB per node - gpuCommBuffer.....2 KiB per node - globalTotal.......64 KiB -``` -or [select](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga849971f43e246d103da1731d0901f2e6) specific deployments -```C++ -int useMPI = 1; -int useGPU = 0; -int useOMP = 0; -Qureg qureg = createCustomQureg(10, 0, useMPI, useGPU, useOMP); -``` - -In lieu of a statevector, we could create a [density matrix](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga1470424b0836ae18b5baab210aedf5d9) -```C++ -Qureg qureg = createDensityQureg(10); -``` -which is also auto-deployed. Note this contains _square_ as many amplitudes as the equal-dimension statevector and ergo requires _square_ as much memory. -```C++ -reportQureg(qureg); -reportQuregParams(qureg); -``` -``` -Qureg (10 qubit density matrix, 1024x1024 qcomps, 16 MiB): - 1 0 … 0 0 - 0 0 … 0 0 - 0 0 … 0 0 - 0 0 … 0 0 - ⋮ - 0 0 … 0 0 - 0 0 … 0 0 - 0 0 … 0 0 - 0 0 … 0 0 - - -Qureg: - ... - [dimension] - isDensMatr.....1 - numQubits......10 - numCols........2^10 = 1024 - numAmps........2^20 = 1048576 - ... - [memory] - cpuAmps...........16 MiB - ... - globalTotal.......16 MiB -``` - -> The spacing between the outputs of those two consecutive QuEST functions was determined by our earlier call to [`setMaxNumReportedSigFigs()`](https://quest-kit.github.io/QuEST/group__debug__reporting.html#ga29413703d609254244d6b13c663e6e06). - - -A density matrix `Qureg` can model classical uncertainty as results from [decoherence](https://quest-kit.github.io/QuEST/group__decoherence.html), and proves useful when simulating quantum operations on a noisy quantum computer. - - -## 4. Prepare an initial state - -In lieu of manually [modifying](https://quest-kit.github.io/QuEST/group__init__amps.html) the state amplitudes, QuEST includes functions to prepare a `Qureg` in some common [initial states](https://quest-kit.github.io/QuEST/group__init__states.html) - -```C++ -initZeroState(qureg); // |0> or |0><0| -initPlusState(qureg); // |+> or |+><+| -initClassicalState(qureg, i); // |i> or |i> The number of printed significant figures above results from our earlier calling of [`setMaxNumReportedSigFigs()`](https://quest-kit.github.io/QuEST/group__debug__reporting.html#ga15d46e5d813f70b587762814964e1994). - - -## 5. Apply operators - -QuEST supports an extensive set of [operators](https://quest-kit.github.io/QuEST/group__operations.html) to effect upon a `Qureg`. -```C++ -int target = 2; -applyHadamard(qureg, target); - -qreal angle = 3.14 / 5; -int targets[] = {4,5,6}; -applyPhaseGadget(qureg, targets, 3, angle); -``` - -> [!IMPORTANT] -> Notice the type of `angle` is [`qreal`](https://quest-kit.github.io/QuEST/group__types.html#ga2d479c159621c76ca6f96abe66f2e69e) rather than the expected `double`. This is a precision agnostic alias for a floating-point, real scalar which allows you to recompile QuEST with a varying [precision](/docs/compile.md#precision) with no modifications to your code. - -### controls - -All unitary operations accept any number of control qubits -```C++ -int controls[] = {0,1,2,3,7,8,9}; -applyMultiControlledSqrtSwap(qureg, controls, 7, targets[0], targets[1]); -``` -and even _control states_ which specify the bits (`0` or `1`) that the respective controls must be in to effect the non-identity operation. -```C++ -int states[] = {0,0,0,1,1,1,0}; -applyMultiStateControlledRotateX(qureg, controls, states, 7, target, angle); -``` - -> [!TIP] -> `C` users can pass inline list arguments using [compound literals](https://en.cppreference.com/w/c/language/compound_literal) -> ```C -> applyMultiControlledMultiQubitNot(qureg, (int[]) {0,1,2}, 3, (int[]) {4,5}, 2); -> ``` -> while `C++` users can pass [vector](https://en.cppreference.com/w/cpp/container/vector) literals or [initializer lists](https://en.cppreference.com/w/cpp/utility/initializer_list), alleviating the need to specify the list lengths. -> ```C++ -> applyMultiControlledMultiQubitNot(qureg, {0,1,2}, {4,5}); -> ``` - -### paulis - -Some operators accept [`PauliStr`](https://quest-kit.github.io/QuEST/structPauliStr.html) which can be [constructed](https://quest-kit.github.io/QuEST/group__paulis__create.html) all sorts of ways - even inline! -```C++ -applyPauliGadget(qureg, getPauliStr("XYZ"), angle); -``` - -> [!TIP] -> Using _one_ QuEST function is _always_ faster than using an equivalent sequence. So -> ```C++ -> applyPauliStr(qureg, getPauliStr("YYYYYYY")); -> ``` -> is _much_ faster than -> ```C++ -> for (int i=0; i<7; i++) -> applyPauliY(qureg, i); -> ``` - -### matrices - -#### `CompMatr1` - -Don't see your operation in the API? You can specify it as a general [matrix](https://quest-kit.github.io/QuEST/group__matrices.html). -```C++ -qcomp x = 1i/sqrt(2); -CompMatr1 matrix = getInlineCompMatr({{-x,x},{-x,-x}}); -applyCompMatr1(qureg, target, matrix); -``` - -> [!IMPORTANT] -> The type [`qcomp`](https://quest-kit.github.io/QuEST/group__types.html#ga4971f489e74bb185b9b2672c14301983) above is a precision agnostic complex scalar, and has beautiful arithmetic overloads! -> ```C++ -> qcomp x = 1.5 + 3.14i; -> qcomp *= 1E3i - 1E-5i; -> ``` -> Beware that in `C++`, `1i` is a _double precision_ literal, so `C++` users should instead -> use the custom precision-agnostic literal `1_i`. -> ```C++ -> qcomp x = 1.5 + 3.14_i; -> ``` - -#### `CompMatr` - -Want a bigger matrix? No problem - they can be [any size](https://quest-kit.github.io/QuEST/group__matrices__create.html#ga634309472d1edf400174680af0685b89), with many ways to [initialise](https://quest-kit.github.io/QuEST/group__matrices__setters.html) them. -```C++ -CompMatr bigmatrix = createCompMatr(8); -setCompMatr(bigmatrix, {{1,2,3,...}}); -applyCompMatr(qureg, ..., bigmatrix); -``` -Matrix elements can be manually modified, though this requires we [synchronise](https://quest-kit.github.io/QuEST/group__matrices__sync.html) them with GPU memory once finished. -```C++ -qindex dim = bigmatrix.numRows; - -// initialise random diagonal unitary -for (qindex r=0; r [!IMPORTANT] -> The created `CompMatr` is a [heap object](https://craftofcoding.wordpress.com/2015/12/07/memory-in-c-the-stack-the-heap-and-static/) and must be [destroyed](https://quest-kit.github.io/QuEST/group__matrices__destroy.html) when we are finished with it, to free up its memory and avoid leaks. -> ```C++ -> destroyCompMatr(bigmatrix); -> ``` -> This is true of any QuEST structure returned by a `create*()` function. It is _not_ true of functions prefixed with `get*()` with are always [stack variables](https://craftofcoding.wordpress.com/2015/12/07/memory-in-c-the-stack-the-heap-and-static/), hence why functions like `getCompMatr1()` can be called inline! - - -#### `FullStateDiagMatr` - -Above, we initialised [`CompMatr`](https://quest-kit.github.io/QuEST/structCompMatr.html) to a diagonal unitary. This is incredibly wasteful; only `256` of its `65536` elements are non-zero! We should instead use [`DiagMatr`](https://quest-kit.github.io/QuEST/structDiagMatr.html) or [`FullStateDiagMatr`](https://quest-kit.github.io/QuEST/structFullStateDiagMatr.html). The latter is even distributed (if chosen by the autodeployer), permitting it to be as large as a `Qureg` itself! -```C++ -FullStateDiagMatr fullmatrix = createFullStateDiagMatr(qureg.numQubits); -``` -and can be [initialised](https://quest-kit.github.io/QuEST/group__matrices__setters.html) in many ways, including from all-`Z` pauli sums! -```C++ -PauliStrSum sum = createInlinePauliStrSum(R"( - 1 II - 1i ZI - 1i IZ - -1 ZZ -)"); - -setFullStateDiagMatrFromPauliStrSum(fullmatrix, sum); -``` -> [!IMPORTANT] -> The argument to `createInlinePauliStrSum` is a multiline string for which the syntax differs between `C` and `C++`; we used the latter above. See examples [`initialisation.c`](/examples/paulis/initialisation.c) and [`initialisation.cpp`](/paulis/matrices/initialisation.cpp) for clarity. - -> [!CAUTION] -> Beware that in distributed settings, because `fullmatrix` _may_ be distributed, we should must exercise extreme caution when modifying its `fullmatrix.cpuElems` directly. - - -A `FullStateDiagMatr` acts upon all qubits of a qureg -```C++ -applyFullStateDiagMatr(qureg, fullmatrix); -``` -and can be raised to an arbitrary power, helpful for example in simulating [quantum spectral methods](https://www.science.org/doi/10.1126/sciadv.abo7484). -```C++ -qcomp exponent = 3.5; -applyFullStateDiagMatrPower(qureg, fullmatrix, exponent); -``` - -Notice the `exponent` is a `qcomp` and ergo permitted to be a complex number. Unitarity requires `exponent` is strictly real, but we can always relax the unitarity validation... - - -#### validation - - -Our example above initialised `CompMatr` to a diagonal because it is tricky to generate random non-diagonal **_unitary_** matrices - and QuEST checks for unitarity! -```C++ -// m * dagger(m) != identity -CompMatr1 m = getCompMatr1({{.1,.2},{.3,.4}}); -applyCompMatr1(qureg, 0, m); -``` -``` -QuEST encountered a validation error during function 'applyCompMatr1': -The given matrix was not (approximately) unitary. -Exiting... -``` -If we're satisfied our matrix _is_ sufficiently approximately unitary, we can [adjust](https://quest-kit.github.io/QuEST/group__debug__validation.html#gae395568df6def76045ec1881fcb4e6d1) or [disable](https://quest-kit.github.io/QuEST/group__debug__validation.html#ga5999824df0785ea88fb2d5b5582f2b46) the validation. -```C++ -// max(norm(m * dagger(m) - identity)) = 0.9025 -setValidationEpsilon(0.903); -applyCompMatr1(qureg, 0, m); -``` - - -### circuits - -QuEST includes a few convenience functions for effecting [QFT](https://quest-kit.github.io/QuEST/group__op__qft.html) and [Trotter](https://quest-kit.github.io/QuEST/group__op__paulistrsum.html) circuits. - -```C++ -applyQuantumFourierTransform(qureg, targets, 3); - -qreal time = .3; -int order = 4; -int reps = 10; -applyTrotterizedPauliStrSumGadget(qureg, sum, time, order, reps); -``` - - - -### measurements - -We can also effect a wide range of non-unitary operations, such as destructive [measurements](https://quest-kit.github.io/QuEST/group__op__measurement.html) -```C++ -int outcome1 = applyQubitMeasurement(qureg, 0); - -qreal prob; -qindex outcome2 = applyMultiQubitMeasurementAndGetProb(qureg, targets, 3, &prob); -``` -and conveniently [report](https://quest-kit.github.io/QuEST/group__types.html#ga2be8a4433585a8d737c02128b4754a03) their outcome. -```C++ -reportScalar("one qubit outcome", outcome1); -reportScalar("three qubit outcome", outcome2); -``` - -> [!IMPORTANT] -> Notice the type of `outcome2` is a [`qindex`](https://quest-kit.github.io/QuEST/group__types.html#ga6017090d3ed4063ee7233e20c213424b) rather than an `int`. This is a larger type which can store much larger numbers without overflow - up to `2^63` - and is always used by the API for many-qubit indices. - -Should we wish to leave the state unnormalised, we can instead use [projectors](https://quest-kit.github.io/QuEST/group__op__projectors.html). - -### decoherence - -Density matrices created with [`createDensityQureg()`](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga1470424b0836ae18b5baab210aedf5d9) can undergo [decoherence](https://quest-kit.github.io/QuEST/group__decoherence.html) channels. - -```C++ -qreal prob = 0.1; -mixDamping(rho, target, prob); -mixDephasing(rho, target, prob); -mixTwoQubitDepolarising(rho, targets[0], targets[1], prob); -``` -which we can specify as inhomogeneous Pauli channels -```C++ -// passing probabilities of X, Y, Z errors respectively -mixPaulis(Qureg qureg, target, .05, .10, .15); -``` -or completely generally as [Kraus maps](https://quest-kit.github.io/QuEST/group__channels.html) and [superoperators](https://quest-kit.github.io/QuEST/group__channels.html)! -```C++ -int numTargets = 1; -int numOperators = 4; - -qreal p = 0.1; -qreal l = 0.3; - -// generalised amplitude damping -KrausMap map = createInlineKrausMap(numTargets, numOperators, { - { - {sqrt(p), 0}, - {0, sqrt(p*(1-l))} - }, { - {0, sqrt(p*l)}, - {0, 0} - }, { - {sqrt((1-p)*(1-l)), 0}, - {0, sqrt(1-p)} - }, { - {0, 0}, - {sqrt((1-p)*l), 0} - } -}); - -int victims[] = {2}; -mixKrausMap(rho, victims, 1, map); -``` -We can even directy mix density matrices together -```C++ -mixQureg(rho1, rho2, prob); -``` - -Sometimes we wish to left-multiply general operators upon density matrices without also right-multiplying their adjoint - i.e. our operators should _not_ be effected as unitaries. We can do this with the `multiply*()` functions. -```C++ -multiplyDiagMatrPower(rho, fullmatrix, 0.5); -``` - - -## 6. Perform calculations - -After so much modification to our state, we will find that its amplitudes have differed substantially. But it's impractical to observe the exponentially-many amplitudes with [`reportQureg()`](https://quest-kit.github.io/QuEST/group__qureg__report.html#ga2a9df2538e537332b1aef8596ce337b2). We can instead give QuEST the [questions](https://quest-kit.github.io/QuEST/group__calculations.html) we wish to answer about the resulting state. - -For example, we can find the [probability](https://quest-kit.github.io/QuEST/group__calc__prob.html) of measurement outcomes _without_ modifying the state. -```C++ -int outcome = 1; -qreal prob1 = calcProbOfQubitOutcome(qureg, target, outcome); - -int qubits[] = {2,3,4}; -int outcomes[] = {0,1,1}; -qreal prob2 = calcProbOfMultiQubitOutcome(qureg, qubits, outcomes, 3); -``` -We can obtain _all_ outcome probabilities in one swoop: -```C++ -qreal probs[8]; -calcProbsOfAllMultiQubitOutcomes(probs, qureg, qubits, 3); -``` - -> [!TIP] -> `C++` users can also obtain the result as a natural `std::vector`. -> ```C++ -> auto probs = calcProbsOfAllMultiQubitOutcomes(qureg, {2,3,4}); -> ``` - -It is similarly trivial to find [expectation values](https://quest-kit.github.io/QuEST/group__calc__expec.html) -```C++ -qreal expec1 = calcExpecPauliStr(qureg, getPauliStr("XYZIII")); -qreal expec2 = calcExpecPauliStrSum(qureg, sum); -qreal expec3 = calcExpecFullStateDiagMatr(qureg, fullmatrix); -``` -or [distance measures](https://quest-kit.github.io/QuEST/group__calc__comparisons.html) between states, including between statevectors and density matrices. -```C++ -qreal pur = calcPurity(rho); -qreal fid = calcFidelity(rho, psi); -qreal dist = calcDistance(rho, psi); -``` - -We can even find reduced density matrices resulting from [partially tracing](https://quest-kit.github.io/QuEST/group__calc__partialtrace.html) out qubits. -```C++ -Qureg reduced = calcPartialTrace(qureg, targets, 3); - -reportScalar("entanglement", calcPurity(reduced)); -``` - -## 7. Report the results - -We've seen above that [scalars](https://quest-kit.github.io/QuEST/group__types.html) can be reported, handling the pretty formatting of real and complex numbers, controlled by settings like [`setMaxNumReportedSigFigs()`](https://quest-kit.github.io/QuEST/group__debug__reporting.html#ga15d46e5d813f70b587762814964e1994). But we can also report every data structure in the QuEST API, such as Pauli strings -```C++ -reportPauliStr( - getInlinePauliStr("XXYYZZ", {5,50, 10,60, 30,40}) -); -``` -``` -YIIIIIIIIIXIIIIIIIIIZIIIIIIIIIZIIIIIIIIIIIIIIIIIIIYIIIIXIIIII -``` -and their weighted sums -```C++ -reportPauliStrSum(sum); -``` -``` -PauliStrSum (4 terms, 160 bytes): - 1 II - i ZI - i IZ - -1 ZZ -``` -All outputs are affected by the [reporter settings](https://quest-kit.github.io/QuEST/group__debug__reporting.html). -```C++ -setMaxNumReportedItems(4,4); -setMaxNumReportedSigFigs(1); -reportCompMatr(bigmatrix); -``` -``` -CompMatr (8 qubits, 256x256 qcomps, 1 MiB): - 0.9-0.5i 0 … 0 0 - 0 0.8-0.6i … 0 0 - ⋮ - 0 0 … -0.5-0.9i 0 - 0 0 … 0 0.4+0.9i -``` - - - -> [!NOTE] -> Facilities for automatically logging to file are coming soon! - - -## 8. Cleanup - -While not strictly necessary before the program ends, it is a good habit to destroy data structures as soon as you are finished with them, freeing their memory. - -```C++ -destroyQureg(qureg); -destroyCompMatr(bigmatrix); -destroyFullStateDiagMatr(fullmatrix); -destroyPauliStrSum(sum); -destroyKrausMap(map); -``` - -## 9. Finalise QuEST - -The **_final_** [step](https://quest-kit.github.io/QuEST/group__environment.html#ga428faad4d68abab20f662273fff27e39) of our program should be to call -```C++ -finalizeQuESTEnv(); -``` -which ensures everything is synchronised, frees accelerator resources, and finalises MPI. -This is important because it ensures: -- _everything is done_, and that distributed nodes that are still working (e.g. haven't yet logged to their own file) are not interrupted by early termination of another node. -- the MPI process ends gracefully, and doesn't spew out messy errors! -- our GPU processes are killed quickly, freeing resources for other processes. - -> [!CAUTION] -> After calling `finalizeQuESTEnv()`, MPI will close and each if being accessed directly by the user, will enter an undefined state. Subsequent calls to MPI routines may return gibberish, and distributed machines will have lost their ability to communicate. It is recommended to call `finalizeQuESTEnv()` immediately before exiting. - -You are now a QuEST expert 🎉 though there are _many_ more functions in the [API](https://quest-kit.github.io/QuEST/group__api.html) not covered here. Go forth and simulate! \ No newline at end of file From e0ba69e400da0aa96fff55cb0ec143d199d195ab Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 21:16:30 +0200 Subject: [PATCH 18/24] added github READMEs to doxygen --- docs/README.md | 6 +++--- docs/architecture.md | 5 +++-- docs/cmake.md | 6 +++--- docs/compile.md | 7 ++++--- docs/compilers.md | 5 +++-- docs/contributing.md | 6 +++--- docs/launch.md | 5 +++-- docs/styleguide.md | 4 +++- docs/v4.md | 8 +++++++- utils/docs/Doxyfile | 30 ++++++++++++++++++++++++------ 10 files changed, 56 insertions(+), 26 deletions(-) diff --git a/docs/README.md b/docs/README.md index cc98e6706..a3845c33d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,12 +1,12 @@ +# 📖  Documentation + - -# 📖  Documentation - > [!IMPORTANT] > QuEST's `v4` documentation is still under construction. diff --git a/docs/architecture.md b/docs/architecture.md index f143c3833..1ad8f3a40 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,11 +1,12 @@ +# 🏗️  Architecture + -# 🏗️  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/cmake.md b/docs/cmake.md index c020df0b7..e0594f202 100644 --- a/docs/cmake.md +++ b/docs/cmake.md @@ -1,13 +1,13 @@ +# ⚙️  CMake + - -# ⚙️  CMake - Version 4 of QuEST includes reworked CMake to support library builds, CMake export, and installation. Here we detail useful variables to configure the compilation of QuEST. If using a Unix-like operating system any of these variables can be set using the `-D` flag when invoking CMake, for example: ``` diff --git a/docs/compile.md b/docs/compile.md index 081f8773b..ac76ed316 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -1,5 +1,8 @@ +# 🛠️  Compile + -# 🛠️  Compile - QuEST can be compiled with [CMake](https://cmake.org/) to make a standalone executable, or an exported library, or a library installed on the system. Compiling is configured with variables supplied by the [`-D` flag](https://cmake.org/cmake/help/latest/command/add_definitions.html) to the [CMake CLI](https://cmake.org/cmake/help/latest/guide/user-interaction/index.html#command-line-cmake-tool). This page details _how_ to compile QuEST for varying purposes and hardwares. @@ -191,7 +192,7 @@ void myfunc() { printf("hello quworld!\n"); } ``` -simply separate them by `;` in `USER_SOURCE`, wrapped in `"`: +simply separate them by `;` in `USER_SOURCE`, wrapped in quotations: ```bash # configure cmake .. -D USER_SOURCE="myfile.cpp;otherfile.cpp" -D OUTPUT_EXE=myexec diff --git a/docs/compilers.md b/docs/compilers.md index cc8e1487f..1a155b249 100644 --- a/docs/compilers.md +++ b/docs/compilers.md @@ -1,12 +1,13 @@ +# 🔧  Compilers + -# 🔧  Compilers - QuEST separates compilation of the **_frontend_**, **_backend_** and the **_tests_**, which have progressively stricter compiler requirements. This page details the specialised compilers necessary to enable specific features hardware accelerators, and lists such compilers which are known to be compatible with QuEST. diff --git a/docs/contributing.md b/docs/contributing.md index e627b08ee..cdeb61d67 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -1,15 +1,15 @@ +# ❤️  Contributing + -# ❤️  Contributing - > [!IMPORTANT] > This page is under construction! -> TODO! In the meantime, feel free to open an issue, a discussion or a pull request, or reach out to `tyson.jones.input@gmail.com`. diff --git a/docs/launch.md b/docs/launch.md index 7a20752eb..1a861c136 100644 --- a/docs/launch.md +++ b/docs/launch.md @@ -1,11 +1,12 @@ +# 🚀  Launching + -# 🚀  Launching - Launching your [compiled](compile.md) QuEST application can be as straightforward as running any other executable, though some additional steps are needed to make use of hardware acceleration. This page how to launch your own QuEST applications on different platforms, how to run the examples and unit tests, how to make use of multithreading, GPU-acceleration, distribution and supercomputer job schedulers, and monitor the hardware utilisation. > **TOC**: diff --git a/docs/styleguide.md b/docs/styleguide.md index 39cf54cd9..19729a9a0 100644 --- a/docs/styleguide.md +++ b/docs/styleguide.md @@ -1,10 +1,12 @@ +# 🎨  Style guide + -# 🎨  Style guide Don't agonise about style - write your code as you see fit and we can address major issues in review/PR. diff --git a/docs/v4.md b/docs/v4.md index e2ef64e25..f14cca99e 100644 --- a/docs/v4.md +++ b/docs/v4.md @@ -1,6 +1,12 @@ - # 🎉  What's new in v4 + + QuEST `v4` has completely overhauled the API, software architecture, algorithms, implementations and testing. This page details the new features, divided into those relevant to _users_, _developers_ who integrate QuEST into larger software stacks, and _contributors_ who develop QuEST or otherwise peep at the source code! > **TOC**: diff --git a/utils/docs/Doxyfile b/utils/docs/Doxyfile index 8db618737..4a721e1c8 100644 --- a/utils/docs/Doxyfile +++ b/utils/docs/Doxyfile @@ -1016,13 +1016,31 @@ WARN_LOGFILE = # Note: If this tag is empty the current directory is searched. # note we include both the include/ headers and corresponding src/api files, -# so that doxygen can find the definitions when INLINE_SOURCES = YES -# note too that we currently exclude the /docs and /examples folders, which -# override the automatic expansions of the README.md sections into separate -# pages under +# so that doxygen can find the definitions when INLINE_SOURCES = YES. +# we also explicitly list each file (rather than just the directory) where we +# want to decide the ordering of the generated doxygen pages, and THEN include +# the entire directory (in case new files are later added therein). +# @todo /examples/ are being ignored below for some reason! INPUT = . \ - ./quest/include ./quest/src/api \ - ./tests ./tests/utils ./tests/unit ./tests/integration ./tests/deprecated + ./docs/v4.md \ + ./docs/tutorial.md \ + ./docs/compile.md \ + ./docs/compilers.md \ + ./docs/cmake.md \ + ./docs/launch.md \ + ./docs/contributing.md \ + ./docs/architecture.md \ + ./docs/styleguide.md \ + ./docs \ + ./examples/README.md \ + ./examples \ + ./quest/include \ + ./quest/src/api \ + ./tests \ + ./tests/utils \ + ./tests/unit \ + ./tests/integration \ + ./tests/deprecated # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses From a40d4979a1f69400a52bbbb646b271f8bb2ab433 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 21:26:24 +0200 Subject: [PATCH 19/24] correcting C++ code tag which was not recognised by the Github Actions doxygen (but was offline, strangely) --- README.md | 21 ++------ docs/compile.md | 4 +- docs/launch.md | 4 +- docs/styleguide.md | 12 ++--- docs/tutorial.md | 118 ++++++++++++++++++++++----------------------- tests/README.md | 2 +- 6 files changed, 74 insertions(+), 87 deletions(-) diff --git a/README.md b/README.md index e581a58ca..78bb7832d 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ To learn more: ## 🎉  Introduction QuEST has a simple interface which is agnostic to whether it's running on CPUs, GPUs or a networked supercomputer. -```C++ +```cpp Qureg qureg = createQureg(30); initRandomPureState(qureg); @@ -116,7 +116,7 @@ qreal prob = calcProbOfQubitOutcome(qureg, 0, outcome); qreal expec = calcExpecPauliStr(qureg, getPauliStr("XYZ")); ``` Yet, it is flexible -```C++ +```cpp mixDepolarising(qureg, targ, prob); mixKrausMap(qureg, targs, ntargs, krausmap); @@ -130,7 +130,7 @@ multiplyCompMatr1(qureg, targ, getInlineCompMatr1( {{1,2i},{3i,4}} )); multiplyDiagMatrPower(qureg, targs, ntargs, diagmatr, exponent); ``` and extremely powerful -```C++ +```cpp setFullStateDiagMatrFromMultiVarFunc(fullmatr, myfunc, ntargsPerVar, nvars); applyFullStateDiagMatrPower(qureg, fullmatr, exponent); @@ -183,15 +183,7 @@ QuEST supports: > [!IMPORTANT] > QuEST v4's documentation is still under construction! -Visit the [docs](docs/README.md) to: - - [see what's new in v4](docs/v4.md) - - [follow the tutorial](docs/tutorial.md) - - [compile with cmake](docs/compile.md) - - [find compatible compilers](docs/compilers.md) - - [launch your simulations](docs/launch.md) - - [view some examples](examples/) - -The [API](https://quest-kit.github.io/QuEST/group__api.html) documentation is divided into the following groups: +Visit the [docs](docs/README.md) for guides and tutorials, or the [API](https://quest-kit.github.io/QuEST/group__api.html) which is divided into: - [calculations](https://quest-kit.github.io/QuEST/group__calculations.html) - [channels](https://quest-kit.github.io/QuEST/group__channels.html) - [debug](https://quest-kit.github.io/QuEST/group__debug.html) @@ -239,11 +231,6 @@ You can also browse QuEST's extensive [tests](https://quest-kit.github.io/QuEST/ - [deprecated test utilities](https://quest-kit.github.io/QuEST/group__deprecatedutils.html) --> -Contributers to QuEST should also check out the: - - [contribution guide](docs/contributing.md) - - [software architecture](docs/architecture.md) - - [style guide](docs/styleguide.md) - --------------------------------- ## 🚀  Getting started diff --git a/docs/compile.md b/docs/compile.md index ac76ed316..7b765781c 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -169,7 +169,7 @@ where - `myexec` is the output executable name, which will be saved in `build`. To compile multiple dependent files, such as -```C++ +```cpp /* myfile.cpp */ #include "quest.h" @@ -183,7 +183,7 @@ int main() { return 0; } ``` -```C++ +```cpp /* otherfile.cpp */ #include diff --git a/docs/launch.md b/docs/launch.md index 1a861c136..198fcb1ff 100644 --- a/docs/launch.md +++ b/docs/launch.md @@ -265,11 +265,11 @@ Performance may be improved by setting other [OpenMP variables](https://www.open OpenMP experts may further benefit from knowing that QuEST's multithreaded source code, confined to [`cpu_subroutines.cpp`](/quest/src/cpu/cpu_subroutines.cpp), is almost exclusively code similar to -```C++ +```cpp #pragma omp parallel for if(qureg.isMultithreaded) for (qindex n=0; n mylist; ``` - whitespace is free; use it wherever it can improve clarity, like to separate subroutines. - ```C++ + ```cpp // i000 = nth local index where all suffix bits are 0 qindex i000 = insertThreeZeroBits(n, braQb1, ketQb2, ketQb1); qindex i0b0 = setBit(i000, ketQb2, braBit2); @@ -54,7 +54,7 @@ Some encouraged conventions include: ``` - use `auto` where it improves readability, discretionarily. Obviously it is better than massive, unimportant types of objects or heavily templated collections, but sometimes knowing the precise type of a primitive is helpful - It is permissable to avoid superfluous braces around single-line branches: - ```C++ + ```cpp if (cond) return x; ``` diff --git a/docs/tutorial.md b/docs/tutorial.md index 8241a19e6..df17a256d 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -8,13 +8,13 @@ --> QuEST is included into a `C` or `C++` project via -```C++ +```cpp #include "quest.h" ``` > [!TIP] > Some of QuEST's deprecated `v3` API can be accessed by specifying `ENABLE_DEPRECATED_API` when [compiling](/docs/compile.md#v3), or defining it before import, i.e. -> ```C++ +> ```cpp > #define ENABLE_DEPRECATED_API 1 > #include "quest.h" > ``` @@ -56,7 +56,7 @@ Of course, the procedure is limited only by the programmers imagination `¯\_( ## 1. Initialise the environment Before calling any other QuEST functions, we must [_initialise_](https://quest-kit.github.io/QuEST/group__environment.html#gab89cfc1bf94265f4503d504b02cf54d4) the QuEST [_environment_](https://quest-kit.github.io/QuEST/group__environment.html). -```C++ +```cpp initQuESTEnv(); ``` This does several things, such as @@ -65,7 +65,7 @@ This does several things, such as - seeding the random number generators (informing measurements and random states), using a [CSPRNG](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator) if available. We could instead forcefully [disable](https://quest-kit.github.io/QuEST/group__environment.html#ga485268e52f838743357e7a4c8c241e57) certain hardware accelerations -```C++ +```cpp int useMPI = 0; int useGPU = 0; int useOMP = 0; @@ -77,7 +77,7 @@ initCustomQuESTEnv(useMPI, useGPU, useOMP); > permits QuEST to choose how to best accelerate subsequently created `Qureg`. We can [view](https://quest-kit.github.io/QuEST/group__environment.html#ga08bf98478c4bf21b0759fa7cd4a97496) the environment configuration at runtime, via -```C++ +```cpp reportQuESTEnv(); ``` which might output something like @@ -140,7 +140,7 @@ QuEST execution environment: ``` We can also [obtain](https://quest-kit.github.io/QuEST/group__environment.html#ga6b9e84b462a999a1fbb9a372f990c491) some of the environment information [programmatically](https://quest-kit.github.io/QuEST/structQuESTEnv.html) -```C++ +```cpp QuESTEnv env = getQuESTEnv(); if (env.isGpuAccelerated) @@ -153,29 +153,29 @@ if (env.isGpuAccelerated) Configuring the environment is ordinarily not necessary, but convenient in certain applications. For example, we may wish our simulations to deterministically obtain the same measurement outcomes and random states as a previous or future run, and ergo choose to [override](https://quest-kit.github.io/QuEST/group__debug__seed.html#ga9e3a6de413901afbf50690573add1587) the default seeds. -```C++ +```cpp unsigned seeds[] = {123u, 1u << 10}; setSeeds(seeds, 2); ``` We may wish further to [adjust](https://quest-kit.github.io/QuEST/group__debug__reporting.html) how subsequent functions will display information to the screen -```C++ +```cpp int maxRows = 8; int maxCols = 4; setMaxNumReportedItems(maxRows, maxCols); setMaxNumReportedSigFigs(3); ``` or [add](https://quest-kit.github.io/QuEST/group__debug__reporting.html#ga29413703d609254244d6b13c663e6e06) extra spacing between QuEST's printed outputs -```C++ +```cpp setNumReportedNewlines(3); ``` Perhaps we also wish to relax the [precision](https://quest-kit.github.io/QuEST/group__debug__validation.html#gae395568df6def76045ec1881fcb4e6d1) with which our future inputs will be asserted unitary or Hermitian -```C++ +```cpp setValidationEpsilon(0.001); ``` but when unitarity _is_ violated, or we otherwise pass an invalid input, we wish to execute a [custom function](https://quest-kit.github.io/QuEST/group__debug__validation.html#ga14b6e7ce08465e36750da3acbc41062f) before exiting. -```C++ +```cpp #include void myErrorHandler(const char *func, const char *msg) { @@ -189,7 +189,7 @@ setInputErrorHandler(myErrorHandler); > [!TIP] > `C++` users may prefer to throw an exception which can be caught, safely permitting execution to continue. In such cases, the erroneous function will _never_ corrupt any passed inputs like `Qureg` nor matrices, nor cause leaks. -> ```C++ +> ```cpp > #include > #include > @@ -205,11 +205,11 @@ setInputErrorHandler(myErrorHandler); ## 3. Create a `Qureg` To [create](https://quest-kit.github.io/QuEST/group__qureg__create.html) a statevector of `10` qubits, we call -```C++ +```cpp Qureg qureg = createQureg(10); ``` which we can [verify](https://quest-kit.github.io/QuEST/group__qureg__report.html#ga2a9df2538e537332b1aef8596ce337b2) has begun in the very boring zero state. -```C++ +```cpp reportQureg(qureg); ``` ``` @@ -229,7 +229,7 @@ Qureg (10 qubit statevector, 1024 qcomps, 16.1 KiB): Behind the scenes, the function `createQureg` did something clever; it consulted the compiled deployments and available hardware to decide whether to distribute `qureg`, or dedicate it persistent GPU memory, and marked whether or not to multithread its subsequent modification. It attempts to choose _optimally_, avoiding gratuitous parallelisation if the overheads outweigh the benefits, or if the hardware devices have insufficient memory. We call this **_auto-deployment_**, and the chosen configuration can be [previewed](https://quest-kit.github.io/QuEST/group__qureg__report.html#ga97d96af7c7ea7b31e32cbe3b25377e09) via -```C++ +```cpp reportQuregParams(qureg); ``` ``` @@ -257,7 +257,7 @@ Qureg: The above output informs us that the `qureg` has not been distributed nor GPU-accelerated, but _will_ be multithreaded. If we so wished, we could [_force_](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga619bbba1cbc2f7f9bbf3d3b86b3f02be) the use of all deployments available to the environment -```C++ +```cpp Qureg qureg = createForcedQureg(10); reportQuregParams(qureg); ``` @@ -284,7 +284,7 @@ Qureg: globalTotal.......64 KiB ``` or [select](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga849971f43e246d103da1731d0901f2e6) specific deployments -```C++ +```cpp int useMPI = 1; int useGPU = 0; int useOMP = 0; @@ -292,11 +292,11 @@ Qureg qureg = createCustomQureg(10, 0, useMPI, useGPU, useOMP); ``` In lieu of a statevector, we could create a [density matrix](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga1470424b0836ae18b5baab210aedf5d9) -```C++ +```cpp Qureg qureg = createDensityQureg(10); ``` which is also auto-deployed. Note this contains _square_ as many amplitudes as the equal-dimension statevector and ergo requires _square_ as much memory. -```C++ +```cpp reportQureg(qureg); reportQuregParams(qureg); ``` @@ -337,14 +337,14 @@ A density matrix `Qureg` can model classical uncertainty as results from [decohe In lieu of manually [modifying](https://quest-kit.github.io/QuEST/group__init__amps.html) the state amplitudes, QuEST includes functions to prepare a `Qureg` in some common [initial states](https://quest-kit.github.io/QuEST/group__init__states.html) -```C++ +```cpp initZeroState(qureg); // |0> or |0><0| initPlusState(qureg); // |+> or |+><+| initClassicalState(qureg, i); // |i> or |i> applyMultiControlledMultiQubitNot(qureg, (int[]) {0,1,2}, 3, (int[]) {4,5}, 2); > ``` > while `C++` users can pass [vector](https://en.cppreference.com/w/cpp/container/vector) literals or [initializer lists](https://en.cppreference.com/w/cpp/utility/initializer_list), alleviating the need to specify the list lengths. -> ```C++ +> ```cpp > applyMultiControlledMultiQubitNot(qureg, {0,1,2}, {4,5}); > ``` ### paulis Some operators accept [`PauliStr`](https://quest-kit.github.io/QuEST/structPauliStr.html) which can be [constructed](https://quest-kit.github.io/QuEST/group__paulis__create.html) all sorts of ways - even inline! -```C++ +```cpp applyPauliGadget(qureg, getPauliStr("XYZ"), angle); ``` > [!TIP] > Using _one_ QuEST function is _always_ faster than using an equivalent sequence. So -> ```C++ +> ```cpp > applyPauliStr(qureg, getPauliStr("YYYYYYY")); > ``` > is _much_ faster than -> ```C++ +> ```cpp > for (int i=0; i<7; i++) > applyPauliY(qureg, i); > ``` @@ -442,7 +442,7 @@ applyPauliGadget(qureg, getPauliStr("XYZ"), angle); #### `CompMatr1` Don't see your operation in the API? You can specify it as a general [matrix](https://quest-kit.github.io/QuEST/group__matrices.html). -```C++ +```cpp qcomp x = 1i/sqrt(2); CompMatr1 matrix = getInlineCompMatr({{-x,x},{-x,-x}}); applyCompMatr1(qureg, target, matrix); @@ -450,26 +450,26 @@ applyCompMatr1(qureg, target, matrix); > [!IMPORTANT] > The type [`qcomp`](https://quest-kit.github.io/QuEST/group__types.html#ga4971f489e74bb185b9b2672c14301983) above is a precision agnostic complex scalar, and has beautiful arithmetic overloads! -> ```C++ +> ```cpp > qcomp x = 1.5 + 3.14i; > qcomp *= 1E3i - 1E-5i; > ``` > Beware that in `C++`, `1i` is a _double precision_ literal, so `C++` users should instead > use the custom precision-agnostic literal `1_i`. -> ```C++ +> ```cpp > qcomp x = 1.5 + 3.14_i; > ``` #### `CompMatr` Want a bigger matrix? No problem - they can be [any size](https://quest-kit.github.io/QuEST/group__matrices__create.html#ga634309472d1edf400174680af0685b89), with many ways to [initialise](https://quest-kit.github.io/QuEST/group__matrices__setters.html) them. -```C++ +```cpp CompMatr bigmatrix = createCompMatr(8); setCompMatr(bigmatrix, {{1,2,3,...}}); applyCompMatr(qureg, ..., bigmatrix); ``` Matrix elements can be manually modified, though this requires we [synchronise](https://quest-kit.github.io/QuEST/group__matrices__sync.html) them with GPU memory once finished. -```C++ +```cpp qindex dim = bigmatrix.numRows; // initialise random diagonal unitary @@ -483,7 +483,7 @@ syncCompMatr(bigmatrix); > [!IMPORTANT] > The created `CompMatr` is a [heap object](https://craftofcoding.wordpress.com/2015/12/07/memory-in-c-the-stack-the-heap-and-static/) and must be [destroyed](https://quest-kit.github.io/QuEST/group__matrices__destroy.html) when we are finished with it, to free up its memory and avoid leaks. -> ```C++ +> ```cpp > destroyCompMatr(bigmatrix); > ``` > This is true of any QuEST structure returned by a `create*()` function. It is _not_ true of functions prefixed with `get*()` with are always [stack variables](https://craftofcoding.wordpress.com/2015/12/07/memory-in-c-the-stack-the-heap-and-static/), hence why functions like `getCompMatr1()` can be called inline! @@ -492,11 +492,11 @@ syncCompMatr(bigmatrix); #### `FullStateDiagMatr` Above, we initialised [`CompMatr`](https://quest-kit.github.io/QuEST/structCompMatr.html) to a diagonal unitary. This is incredibly wasteful; only `256` of its `65536` elements are non-zero! We should instead use [`DiagMatr`](https://quest-kit.github.io/QuEST/structDiagMatr.html) or [`FullStateDiagMatr`](https://quest-kit.github.io/QuEST/structFullStateDiagMatr.html). The latter is even distributed (if chosen by the autodeployer), permitting it to be as large as a `Qureg` itself! -```C++ +```cpp FullStateDiagMatr fullmatrix = createFullStateDiagMatr(qureg.numQubits); ``` and can be [initialised](https://quest-kit.github.io/QuEST/group__matrices__setters.html) in many ways, including from all-`Z` pauli sums! -```C++ +```cpp PauliStrSum sum = createInlinePauliStrSum(R"( 1 II 1i ZI @@ -514,11 +514,11 @@ setFullStateDiagMatrFromPauliStrSum(fullmatrix, sum); A `FullStateDiagMatr` acts upon all qubits of a qureg -```C++ +```cpp applyFullStateDiagMatr(qureg, fullmatrix); ``` and can be raised to an arbitrary power, helpful for example in simulating [quantum spectral methods](https://www.science.org/doi/10.1126/sciadv.abo7484). -```C++ +```cpp qcomp exponent = 3.5; applyFullStateDiagMatrPower(qureg, fullmatrix, exponent); ``` @@ -530,7 +530,7 @@ Notice the `exponent` is a `qcomp` and ergo permitted to be a complex number. Un Our example above initialised `CompMatr` to a diagonal because it is tricky to generate random non-diagonal **_unitary_** matrices - and QuEST checks for unitarity! -```C++ +```cpp // m * dagger(m) != identity CompMatr1 m = getCompMatr1({{.1,.2},{.3,.4}}); applyCompMatr1(qureg, 0, m); @@ -541,7 +541,7 @@ The given matrix was not (approximately) unitary. Exiting... ``` If we're satisfied our matrix _is_ sufficiently approximately unitary, we can [adjust](https://quest-kit.github.io/QuEST/group__debug__validation.html#gae395568df6def76045ec1881fcb4e6d1) or [disable](https://quest-kit.github.io/QuEST/group__debug__validation.html#ga5999824df0785ea88fb2d5b5582f2b46) the validation. -```C++ +```cpp // max(norm(m * dagger(m) - identity)) = 0.9025 setValidationEpsilon(0.903); applyCompMatr1(qureg, 0, m); @@ -552,7 +552,7 @@ applyCompMatr1(qureg, 0, m); QuEST includes a few convenience functions for effecting [QFT](https://quest-kit.github.io/QuEST/group__op__qft.html) and [Trotter](https://quest-kit.github.io/QuEST/group__op__paulistrsum.html) circuits. -```C++ +```cpp applyQuantumFourierTransform(qureg, targets, 3); qreal time = .3; @@ -566,14 +566,14 @@ applyTrotterizedPauliStrSumGadget(qureg, sum, time, order, reps); ### measurements We can also effect a wide range of non-unitary operations, such as destructive [measurements](https://quest-kit.github.io/QuEST/group__op__measurement.html) -```C++ +```cpp int outcome1 = applyQubitMeasurement(qureg, 0); qreal prob; qindex outcome2 = applyMultiQubitMeasurementAndGetProb(qureg, targets, 3, &prob); ``` and conveniently [report](https://quest-kit.github.io/QuEST/group__types.html#ga2be8a4433585a8d737c02128b4754a03) their outcome. -```C++ +```cpp reportScalar("one qubit outcome", outcome1); reportScalar("three qubit outcome", outcome2); ``` @@ -587,19 +587,19 @@ Should we wish to leave the state unnormalised, we can instead use [projectors]( Density matrices created with [`createDensityQureg()`](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga1470424b0836ae18b5baab210aedf5d9) can undergo [decoherence](https://quest-kit.github.io/QuEST/group__decoherence.html) channels. -```C++ +```cpp qreal prob = 0.1; mixDamping(rho, target, prob); mixDephasing(rho, target, prob); mixTwoQubitDepolarising(rho, targets[0], targets[1], prob); ``` which we can specify as inhomogeneous Pauli channels -```C++ +```cpp // passing probabilities of X, Y, Z errors respectively mixPaulis(Qureg qureg, target, .05, .10, .15); ``` or completely generally as [Kraus maps](https://quest-kit.github.io/QuEST/group__channels.html) and [superoperators](https://quest-kit.github.io/QuEST/group__channels.html)! -```C++ +```cpp int numTargets = 1; int numOperators = 4; @@ -627,12 +627,12 @@ int victims[] = {2}; mixKrausMap(rho, victims, 1, map); ``` We can even directy mix density matrices together -```C++ +```cpp mixQureg(rho1, rho2, prob); ``` Sometimes we wish to left-multiply general operators upon density matrices without also right-multiplying their adjoint - i.e. our operators should _not_ be effected as unitaries. We can do this with the `multiply*()` functions. -```C++ +```cpp multiplyDiagMatrPower(rho, fullmatrix, 0.5); ``` @@ -642,7 +642,7 @@ multiplyDiagMatrPower(rho, fullmatrix, 0.5); After so much modification to our state, we will find that its amplitudes have differed substantially. But it's impractical to observe the exponentially-many amplitudes with [`reportQureg()`](https://quest-kit.github.io/QuEST/group__qureg__report.html#ga2a9df2538e537332b1aef8596ce337b2). We can instead give QuEST the [questions](https://quest-kit.github.io/QuEST/group__calculations.html) we wish to answer about the resulting state. For example, we can find the [probability](https://quest-kit.github.io/QuEST/group__calc__prob.html) of measurement outcomes _without_ modifying the state. -```C++ +```cpp int outcome = 1; qreal prob1 = calcProbOfQubitOutcome(qureg, target, outcome); @@ -651,32 +651,32 @@ int outcomes[] = {0,1,1}; qreal prob2 = calcProbOfMultiQubitOutcome(qureg, qubits, outcomes, 3); ``` We can obtain _all_ outcome probabilities in one swoop: -```C++ +```cpp qreal probs[8]; calcProbsOfAllMultiQubitOutcomes(probs, qureg, qubits, 3); ``` > [!TIP] > `C++` users can also obtain the result as a natural `std::vector`. -> ```C++ +> ```cpp > auto probs = calcProbsOfAllMultiQubitOutcomes(qureg, {2,3,4}); > ``` It is similarly trivial to find [expectation values](https://quest-kit.github.io/QuEST/group__calc__expec.html) -```C++ +```cpp qreal expec1 = calcExpecPauliStr(qureg, getPauliStr("XYZIII")); qreal expec2 = calcExpecPauliStrSum(qureg, sum); qreal expec3 = calcExpecFullStateDiagMatr(qureg, fullmatrix); ``` or [distance measures](https://quest-kit.github.io/QuEST/group__calc__comparisons.html) between states, including between statevectors and density matrices. -```C++ +```cpp qreal pur = calcPurity(rho); qreal fid = calcFidelity(rho, psi); qreal dist = calcDistance(rho, psi); ``` We can even find reduced density matrices resulting from [partially tracing](https://quest-kit.github.io/QuEST/group__calc__partialtrace.html) out qubits. -```C++ +```cpp Qureg reduced = calcPartialTrace(qureg, targets, 3); reportScalar("entanglement", calcPurity(reduced)); @@ -685,7 +685,7 @@ reportScalar("entanglement", calcPurity(reduced)); ## 7. Report the results We've seen above that [scalars](https://quest-kit.github.io/QuEST/group__types.html) can be reported, handling the pretty formatting of real and complex numbers, controlled by settings like [`setMaxNumReportedSigFigs()`](https://quest-kit.github.io/QuEST/group__debug__reporting.html#ga15d46e5d813f70b587762814964e1994). But we can also report every data structure in the QuEST API, such as Pauli strings -```C++ +```cpp reportPauliStr( getInlinePauliStr("XXYYZZ", {5,50, 10,60, 30,40}) ); @@ -694,7 +694,7 @@ reportPauliStr( YIIIIIIIIIXIIIIIIIIIZIIIIIIIIIZIIIIIIIIIIIIIIIIIIIYIIIIXIIIII ``` and their weighted sums -```C++ +```cpp reportPauliStrSum(sum); ``` ``` @@ -705,7 +705,7 @@ PauliStrSum (4 terms, 160 bytes): -1 ZZ ``` All outputs are affected by the [reporter settings](https://quest-kit.github.io/QuEST/group__debug__reporting.html). -```C++ +```cpp setMaxNumReportedItems(4,4); setMaxNumReportedSigFigs(1); reportCompMatr(bigmatrix); @@ -729,7 +729,7 @@ CompMatr (8 qubits, 256x256 qcomps, 1 MiB): While not strictly necessary before the program ends, it is a good habit to destroy data structures as soon as you are finished with them, freeing their memory. -```C++ +```cpp destroyQureg(qureg); destroyCompMatr(bigmatrix); destroyFullStateDiagMatr(fullmatrix); @@ -740,7 +740,7 @@ destroyKrausMap(map); ## 9. Finalise QuEST The **_final_** [step](https://quest-kit.github.io/QuEST/group__environment.html#ga428faad4d68abab20f662273fff27e39) of our program should be to call -```C++ +```cpp finalizeQuESTEnv(); ``` which ensures everything is synchronised, frees accelerator resources, and finalises MPI. diff --git a/tests/README.md b/tests/README.md index 7525aff44..adee0a8ab 100644 --- a/tests/README.md +++ b/tests/README.md @@ -15,7 +15,7 @@ The subdirectories are: - [`deprecated`](deprecated/) containing `v3`'s tests and utilities, only used when explicitly [activated](/docs/compile.md#v3). The tests use [Catch2](https://github.com/catchorg/Catch2) and are generally structured as -```C++ +```cpp TEST_CASE( "someApiFunc", "[funcs]" ) { PREPARE_TEST(...) From 24adb58c9dcc9b59cdac435b33b0a77afed5163a Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 21:51:14 +0200 Subject: [PATCH 20/24] removing bold-syntax unsupported by doxygen --- docs/compile.md | 2 +- docs/compilers.md | 2 +- docs/launch.md | 2 +- docs/tutorial.md | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/compile.md b/docs/compile.md index 7b765781c..c1b991c1c 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -107,7 +107,7 @@ On most platforms (with the exception of Windows), this is automatic with the co cmake .. -D CMAKE_BUILD_TYPE=Release ``` -When compiling on **Windows** however (using [Visual Studio](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators)), or otherwise using a "[_multi-config generator_](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#other-generators)", we must always supply the build type at **_build time_** via [`config`](https://cmake.org/cmake/help/latest/manual/cmake.1.html#cmdoption-cmake-build-config): +When compiling on **Windows** however (using [Visual Studio](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators)), or otherwise using a "[_multi-config generator_](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#other-generators)", we must always supply the build type at _build time_ via [`config`](https://cmake.org/cmake/help/latest/manual/cmake.1.html#cmdoption-cmake-build-config): ```bash # build cmake --build . --config Release diff --git a/docs/compilers.md b/docs/compilers.md index 1a155b249..776d6b92c 100644 --- a/docs/compilers.md +++ b/docs/compilers.md @@ -8,7 +8,7 @@ @author Tyson Jones --> -QuEST separates compilation of the **_frontend_**, **_backend_** and the **_tests_**, which have progressively stricter compiler requirements. +QuEST separates compilation of the _frontend_, _backend_ and the _tests_, which have progressively stricter compiler requirements. This page details the specialised compilers necessary to enable specific features hardware accelerators, and lists such compilers which are known to be compatible with QuEST. diff --git a/docs/launch.md b/docs/launch.md index 198fcb1ff..3a48b0299 100644 --- a/docs/launch.md +++ b/docs/launch.md @@ -222,7 +222,7 @@ It is prudent to choose as many threads as your CPU(s) have total hardware threa > [!NOTE] -> When running [distributed](#distribution), variable `OMP_NUM_THREADS` specifies the number of threads _per node_ and so should ordinarily be the number of hardware threads (or cores) **_per machine_**. +> When running [distributed](#distribution), variable `OMP_NUM_THREADS` specifies the number of threads _per node_ and so should ordinarily be the number of hardware threads (or cores) _per machine_. ### Monitoring utilisation diff --git a/docs/tutorial.md b/docs/tutorial.md index df17a256d..9af42e3ec 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -228,7 +228,7 @@ Qureg (10 qubit statevector, 1024 qcomps, 16.1 KiB): Behind the scenes, the function `createQureg` did something clever; it consulted the compiled deployments and available hardware to decide whether to distribute `qureg`, or dedicate it persistent GPU memory, and marked whether or not to multithread its subsequent modification. It attempts to choose _optimally_, avoiding gratuitous parallelisation if the overheads outweigh the benefits, or if the hardware devices have insufficient memory. -We call this **_auto-deployment_**, and the chosen configuration can be [previewed](https://quest-kit.github.io/QuEST/group__qureg__report.html#ga97d96af7c7ea7b31e32cbe3b25377e09) via +We call this _auto-deployment_, and the chosen configuration can be [previewed](https://quest-kit.github.io/QuEST/group__qureg__report.html#ga97d96af7c7ea7b31e32cbe3b25377e09) via ```cpp reportQuregParams(qureg); ``` @@ -529,7 +529,7 @@ Notice the `exponent` is a `qcomp` and ergo permitted to be a complex number. Un #### validation -Our example above initialised `CompMatr` to a diagonal because it is tricky to generate random non-diagonal **_unitary_** matrices - and QuEST checks for unitarity! +Our example above initialised `CompMatr` to a diagonal because it is tricky to generate random non-diagonal _unitary_ matrices - and QuEST checks for unitarity! ```cpp // m * dagger(m) != identity CompMatr1 m = getCompMatr1({{.1,.2},{.3,.4}}); @@ -739,7 +739,7 @@ destroyKrausMap(map); ## 9. Finalise QuEST -The **_final_** [step](https://quest-kit.github.io/QuEST/group__environment.html#ga428faad4d68abab20f662273fff27e39) of our program should be to call +The _final_ [step](https://quest-kit.github.io/QuEST/group__environment.html#ga428faad4d68abab20f662273fff27e39) of our program should be to call ```cpp finalizeQuESTEnv(); ``` From f6bfe3c9e078cf48fc78a6354fa57d9259719bf7 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 22:28:56 +0200 Subject: [PATCH 21/24] patch doxygen hyperlinks (partially) this still has an issue; the are defined globally, so different files with same-name sections are conflicting --- docs/compile.md | 68 ++++++++++++++++++++- docs/compilers.md | 29 +++++++++ docs/launch.md | 79 +++++++++++++++++++++++++ docs/tutorial.md | 147 +++++++++++++++++++++++++++++++++++++++------- docs/v4.md | 17 ++++++ 5 files changed, 317 insertions(+), 23 deletions(-) diff --git a/docs/compile.md b/docs/compile.md index c1b991c1c..e0de5a5ef 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -49,6 +49,10 @@ Compiling is configured with variables supplied by the [`-D` flag](https://cmake ------------------ + + + + ## Basic Compilation is a two-step process which can generate lots of temporary files and so should be performed in a `build/` folder to avoid clutter. From the `QuEST/` root, run (in terminal): @@ -96,6 +100,10 @@ How _boring_! We must pass additional arguments in order to link QuEST to our ow ------------------ + + + + ## Optimising QuEST's source code is careful to enable a myriad of optimisations such as [inlining](https://en.wikipedia.org/wiki/Inline_expansion), [loop unrolling](https://en.wikipedia.org/wiki/Loop_unrolling), [auto-vectorisation](https://en.wikipedia.org/wiki/Automatic_vectorization) and [cache optimisations](https://en.wikipedia.org/wiki/Cache_replacement_policies). To utilise them fully, we must instruct our compilers to enable them; like we might do with the [`-O3`](https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html) flag when invoking a compiler like `gcc` directly. @@ -142,10 +150,14 @@ Read more about CMake generator configurations [here](https://cmake.org/cmake/he ------------------ + + + + ## Linking QuEST can be pre-compiled and later linked to other binaries, _or_ compiled directly alongside the user's source code. -We focus on the latter use-case, common among scientists when writing simulation scripts. Users seeking to integrate QuEST into larger stacks are likely already familiar with linking libraries through CMake and should check out [`cmake.md`](/docs/cmake.md) directly. +We focus on the latter use-case, common among scientists when writing simulation scripts. Users seeking to integrate QuEST into larger stacks are likely already familiar with linking libraries through CMake and should check out [`cmake.md`](cmake.md) directly. To compile a `C` or `C++` file such as ```C @@ -218,8 +230,15 @@ to your project as a library! ------------------ + + + ## Configuring + + + + ### Precision QuEST's numerical precision can be configured at compile-time, informing what _type_, and ergo how many _bytes_, are used to represent each `qreal` (a floating-point real number) and `qcomp` (a complex amplitude). This affects the memory used by each `Qureg`, but also the user-facing `qreal` and `qcomp` types, as detailed below. Reducing the precision accelerates QuEST at the cost of worsened numerical accuracy. @@ -248,6 +267,9 @@ The values inform types: > When enabling [GPU-acceleration](#gpu-acceleration), the precision _must_ be set to `1` or `2` since GPUs do not support quad precision. + + + ### Compilers If multiple compilers are installed, you can choose which to use to compile your `C` and `C++` sources (the latter including the QuEST source) with respective configure-time commands: @@ -263,6 +285,9 @@ These compilers will also be used as the _host compilers_ (around which bespoke > It is _not_ correct to specify GPU and MPI compilers, like `nvcc` or `mpicc`, via the above flags. See the respective [GPU](#gpu-acceleration) and [MPI](#distribution) sections. + + + ### Flags @@ -290,6 +315,10 @@ QuEST itself accepts a variety of its preprocessors (mostly related to testing) ------------------ + + + + ## Examples To compile all of QuEST's [`examples/`](/examples/), use @@ -309,8 +338,16 @@ as elaborated upon in [`launch.md`](launch.md#tests). ------------------ + + + + ## Tests + + + + ### v4 To compile QuEST's latest unit and integration tests, use @@ -324,6 +361,10 @@ cmake --build . ``` This will compile an executable `tests` in subdirectory `build/tests/`, which can be run as explained in [`launch.md`](launch.md#tests). + + + + ### v3 QuEST's deprecated v3 API has its own unit tests which can be additionally compiled (_except_ on Windows) via @@ -340,6 +381,10 @@ and run as explained in [`launch.md`](launch.md#v3). ------------------ + + + + ## Multithreading Multithreading allows multiple cores of a CPU, or even multiple connected CPUs, to cooperatively perform and ergo accelerate QuEST's expensive functions. Practically all modern computers have the capacity for, and benefit from, multithreading. Note it requires that the CPUs have shared memory (such as through [NUMA](https://learn.microsoft.com/en-us/windows/win32/procthread/numa-support)) and so ergo live in the same machine. CPUs on _different_ machines, connected via a network, can be parallelised over using [distribution](#distribution). @@ -373,6 +418,9 @@ The number of threads over which to parallelise QuEST's execution is chosen thro ------------------ + + + ## GPU-acceleration QuEST's core functions perform simple mathematical transformations on very large arrays, and are ergo well suited to parallelisation using general purpose GPUs. This involves creating persistent memory in the GPU VRAM which mirrors the ordinary CPU memory in RAM, and dispatching the transformations to the GPU, updating the GPU memory. The greater number of cores and massive internal memory bandwidth of the GPU can make this extraordinarily faster than using multithreading. @@ -380,6 +428,10 @@ QuEST's core functions perform simple mathematical transformations on very large QuEST supports parallelisation using both NVIDIA GPUs (using CUDA) and AMD GPUs (using HIP). Using either requires obtaining a specialised compiler and passing some GPU-specific compiler flags. + + + + ### NVIDIA > TODO! @@ -417,6 +469,9 @@ cmake --build . --parallel See [`launch.md`](launch.md#gpu-acceleration) for information on + + + ### AMD > TODO! @@ -456,6 +511,9 @@ The compiled executable can be run like any other, though the GPU behaviour can ------------------ + + + ## cuQuantum When compiling for NVIDIA GPUs, you can choose to optionally enable [_cuQuantum_](https://docs.nvidia.com/cuda/cuquantum/latest/index.html). This will replace some of QuEST's custom GPU functions with [_cuStateVec_](https://docs.nvidia.com/cuda/cuquantum/latest/custatevec/index.html) routines which are likely to use tailored optimisations for your particular GPU and ergo run faster. @@ -490,6 +548,10 @@ No other changes are necessary, nor does cuQuantum affect [hybridising](#multi-g ------------------ + + + + ## Distribution Because statevectors grow exponentially with the number of simulated qubits, it is easy to run out of memory. In such settings, we may seek to use _distribution_ whereby multiple cooperating machines on a network each store a tractable partition of the state. Distribution can also be useful to speed up our simulations, when the benefit of additional parallelisation outweighs the inter-machine communication penalties. @@ -518,6 +580,10 @@ Note that distributed executables are launched in a distinct way to the other de ------------------ + + + + ## Multi-GPU > TODO! diff --git a/docs/compilers.md b/docs/compilers.md index 776d6b92c..ef5367a3e 100644 --- a/docs/compilers.md +++ b/docs/compilers.md @@ -35,6 +35,9 @@ known to be compatible with QuEST. --------------- + + + ## Frontend [![Languages](https://img.shields.io/badge/C-11-ff69b4.svg)](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3631.pdf) @@ -50,6 +53,10 @@ User code can be written in either `C11` or `C++14`, and has so far been tested --------------- + + + + ## Backend [![Languages](https://img.shields.io/badge/C++-17-ff69b4.svg)](https://en.cppreference.com/w/cpp/17) @@ -57,6 +64,9 @@ User code can be written in either `C11` or `C++14`, and has so far been tested The backend is divided into subdirectories [`api/`](/quest/src/api), [`core/`](/quest/src/core), [`comm/`](/quest/src/comm), [`cpu/`](/quest/src/cpu) and [`gpu/`](/quest/src/gpu). All can be compiled with a generic `C++17` compiler, but enabling distribution, multithreading and GPU-acceleration requires using specialised compilers for the latter three. Each can be toggled and compiled independently. Note however that tightly-coupled multi-GPU simulations (`comm` + `gpu`) can be accelerated using bespoke compilers, and use of [cuQuantum](https://developer.nvidia.com/cuquantum-sdk) requires modern compilers (`gpu + cuquantum`), detailed below. + + + ### comm Enabling distribution requires compiling `comm/` with an [MPI](https://en.wikipedia.org/wiki/Message_Passing_Interface)-compatible compiler, which has so far been tested with @@ -68,6 +78,10 @@ Enabling distribution requires compiling `comm/` with an [MPI](https://en.wikipe when wrapping all previously mentioned compilers. + + + + ### cpu Enabling multithreading requires compiling `cpu/` with an [OpenMP](https://www.openmp.org/)-compatible compiler. Versions @@ -77,18 +91,29 @@ Enabling multithreading requires compiling `cpu/` with an [OpenMP](https://www.o have been explicitly tested, as used by the aforementioned compilers. + + + ### gpu Enabling acceleration on NVIDIA or AMD GPUs requires compiling `gpu/` with a [CUDA](https://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/) or [ROCm](https://rocm.docs.amd.com/en/docs-6.0.2/) compiler respectively. These must be compatible with [Thrust](https://developer.nvidia.com/thrust) and [rocThrust](https://github.com/ROCm/rocThrust) respectively. QuEST v4 has been so far tested with - [cuda](https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html) 11 - [cuda](https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html) 12 + + + + ### comm + gpu Simultaneously emabling both distribution _and_ GPU-acceleration is possible with use of the separate compilers above. However, simulation can be accelerated by using a [CUDA-aware MPI](https://developer.nvidia.com/blog/introduction-cuda-aware-mpi/) compiler, enabling QuEST to use [GPUDirect](https://developer.nvidia.com/gpudirect) and avoid superfluous exchanges of CPU and GPU memories. So far, QuEST has been tested with: - [UCX](https://openucx.org/) 1.13 - [UCX](https://openucx.org/) 1.15 + + + + ### gpu + cuquantum Enabling [cuQuantum](https://developer.nvidia.com/cuquantum-sdk) on NVIDIA GPUs with [compute-capability](https://developer.nvidia.com/cuda-gpus) >= `7.0` requires use of a modern CUDA compiler, specifically @@ -98,6 +123,10 @@ Enabling [cuQuantum](https://developer.nvidia.com/cuquantum-sdk) on NVIDIA GPUs --------------- + + + + ## Tests [![Languages](https://img.shields.io/badge/C++-20-ff69b4.svg)](https://en.cppreference.com/w/cpp/20) diff --git a/docs/launch.md b/docs/launch.md index 3a48b0299..e62c9bc61 100644 --- a/docs/launch.md +++ b/docs/launch.md @@ -40,6 +40,9 @@ Launching your [compiled](compile.md) QuEST application can be as straightforwar --------------------- + + + ## Examples > See [`compile.md`](compile.md#examples) for instructions on compiling the examples. @@ -93,10 +96,18 @@ Must pass single cmd-line argument: --------------------- + + + + ## Tests > See [`compile.md`](compile.md#tests) for instructions on compiling the `v4` and `v3` unit tests. + + + + ### v4 QuEST's unit and integration tests are compiled into executable `tests` within the `tests/` subdirectory, and can be directly run from within the `build` folder via @@ -169,6 +180,10 @@ Test project /build Alas tests launched in this way cannot be deployed with distribution. + + + + ### v3 The deprecated tests, when [compiled](compile.md#v3), can be run from the `build` directory via @@ -194,12 +209,20 @@ ctest --------------------- + + + + ## Multithreading > [!NOTE] > Parallelising QuEST over multiple cores and CPUs requires first compiling with > multithreading enabled, as detailed in [`compile.md`](compile.md#multithreading). + + + + ### Choosing threads The number of [threads](https://www.openmp.org/spec-html/5.0/openmpsu1.html) to use is decided before launching the compiled executable, using the [`OMP_NUM_THREADS`](https://www.openmp.org/spec-html/5.0/openmpse50.html) environment variable. @@ -225,6 +248,10 @@ It is prudent to choose as many threads as your CPU(s) have total hardware threa > When running [distributed](#distribution), variable `OMP_NUM_THREADS` specifies the number of threads _per node_ and so should ordinarily be the number of hardware threads (or cores) _per machine_. + + + + ### Monitoring utilisation @@ -253,6 +280,10 @@ Note however that QuEST will not leverage multithreading at runtime when either: Usage of multithreading can be (inadvisably) forced using [`createForcedQureg()`](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga619bbba1cbc2f7f9bbf3d3b86b3f02be) or [`createCustomQureg()`](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga849971f43e246d103da1731d0901f2e6). + + + + ### Improving performance Performance may be improved by setting other [OpenMP variables](https://www.openmp.org/spec-html/5.0/openmpch6.html). Keep in mind that for large `Qureg`, QuEST's runtime is dominated by the costs of modifying large memory structures during long, uninterrupted loops: namely the updating of statevector amplitudes. Some sensible settings include @@ -290,11 +321,19 @@ and never specifies [`schedule`](https://rookiehpc.org/openmp/docs/schedule/inde --------------------- + + + ## GPU-acceleration > [!NOTE] > Using GPU-acceleration requires first compiling QuEST with `CUDA` or `HIP` enabled (to utilise NVIDIA and AMD GPUs respectively) as detailed in [`compile.md`](compile.md#gpu-acceleration). + + + + + ### Launching The compiled executable is launched like any other, via @@ -305,6 +344,10 @@ The compiled executable is launched like any other, via Using _multiple_ available GPUs, regardless of whether they are local or distributed, is done through additionally enabling [distribution](#multi-gpu). + + + + ### Monitoring @@ -345,6 +388,10 @@ Note however that GPU-acceleration might not be leveraged at runtime when either Usage of GPU-acceleration can be (inadvisably) forced using [`createForcedQureg()`](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga619bbba1cbc2f7f9bbf3d3b86b3f02be) or [`createCustomQureg()`](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga849971f43e246d103da1731d0901f2e6). + + + + ### Configuring There are a plethora of [environment variables](https://askubuntu.com/questions/58814/how-do-i-add-environment-variables) which be used to control the execution on [NVIDIA](https://docs.nvidia.com/cuda/cuda-c-programming-guide/#env-vars) and [AMD](https://rocm.docs.amd.com/projects/HIP/en/docs-develop/reference/env_variables.html) GPUs. We highlight only some below. @@ -356,6 +403,9 @@ There are a plethora of [environment variables](https://askubuntu.com/questions/ + + + ### Benchmarking Beware that the CPU dispatches tasks to the GPU _asynchronously_. Control flow returns immediately to the CPU, which will proceed to other duties (like dispatching the next several quantum operation's worth of instructions to the GPU) while the GPU undergoes independent computation (goes _brrrrr_). @@ -367,6 +417,10 @@ However, it _does_ mean codes which seeks to benchmark QuEST must be careful to --------------------- + + + + ## Distribution @@ -378,6 +432,10 @@ However, it _does_ mean codes which seeks to benchmark QuEST must be careful to > Simultaneously using distribution _and_ GPU-acceleration introduces additional considerations detailed in the [proceeding section](#multi-gpu). + + + + ### Launching A distributed QuEST executable called `myexec` can be launched and distributed over (e.g.) `32` nodes using [`mpirun`](https://www.open-mpi.org/doc/v4.1/man1/mpirun.1.php) with the @@ -413,6 +471,9 @@ mpirun -np 1024 --oversubscribe ./mytests ``` + + + ### Configuring @@ -420,6 +481,9 @@ mpirun -np 1024 --oversubscribe ./mytests > - detail environment variables + + + ### Benchmarking QuEST strives to reduce inter-node communication when performing distributed simulation, which can otherwise dominate runtime. Between these rare communications, nodes work in complete independence and are likely to desynchronise, especially when performing operations with non-uniform loads. In fact, many-controlled quantum gates are skipped by non-participating nodes which would otherwise wait idly! @@ -434,6 +498,9 @@ It is ergo always prudent to explicitly call [`syncQuESTEnv()`](https://quest-ki --------------------- + + + ## Multi-GPU @@ -460,6 +527,10 @@ It is ergo always prudent to explicitly call [`syncQuESTEnv()`](https://quest-ki --------------------- + + + + ## Supercomputers A QuEST executable is launched like any other in supercomputing settings, including when distributed. @@ -470,6 +541,11 @@ For convenience however, we offer some example [SLURM](https://slurm.schedmd.com > These submission scripts are only illustrative. It is likely the necessary configuration and commands on > your own supercomputing facility differs! + + + + + ### SLURM 4 machines each with 8 CPUs: @@ -502,6 +578,9 @@ srun ./myexec + + + ### PBS 4 machines each with 8 CPUs: diff --git a/docs/tutorial.md b/docs/tutorial.md index 9af42e3ec..fc4379cb7 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -29,31 +29,36 @@ Simulation typically proceeds as: 6. Perform [calculations](https://quest-kit.github.io/QuEST/group__calculations.html), potentially using [Pauli](https://quest-kit.github.io/QuEST/group__paulis.html) observables. 7. [Report](https://quest-kit.github.io/QuEST/group__types.html) or log the results to file. 8. Destroy any heap-allocated [`Qureg`](https://quest-kit.github.io/QuEST/group__qureg__destroy.html) or [matrices](https://quest-kit.github.io/QuEST/group__matrices__destroy.html). -8. [Finalise](https://quest-kit.github.io/QuEST/group__environment.html#ga428faad4d68abab20f662273fff27e39) the QuEST environment. +9. [Finalise](https://quest-kit.github.io/QuEST/group__environment.html#ga428faad4d68abab20f662273fff27e39) the QuEST environment. Of course, the procedure is limited only by the programmers imagination `¯\_(ツ)_/¯` Let's see an example of these steps below. > **TOC**: -> - [1. Initialise the environment](#1-initialise-the-environment) -> - [2. Configure the environment](#2-configure-the-environment) -> - [3. Create a `Qureg`](#3-create-a--qureg-) -> - [4. Prepare an initial state](#4-prepare-an-initial-state) -> - [5. Apply operators](#5-apply-operators) +> - [Initialise the environment](#initialise-the-environment) +> - [Configure the environment](#configure-the-environment) +> - [Create a `Qureg`](#create-a-qureg) +> - [Prepare an initial state](#prepare-an-initial-state) +> - [Apply operators](#apply-operators) > * [controls](#controls) > * [paulis](#paulis) > * [matrices](#matrices) > * [circuits](#circuits) > * [measurements](#measurements) > * [decoherence](#decoherence) -> - [6. Perform calculations](#6-perform-calculations) -> - [7. Report the results](#7-report-the-results) -> - [8. Cleanup](#8-cleanup) -> - [9. Finalise QuEST](#9-finalise-quest) +> - [Perform calculations](#perform-calculations) +> - [Report the results](#report-the-results) +> - [Cleanup](#cleanup) +> - [Finalise QuEST](#finalise-quest) +-------------------------------------------- + + + + +## Initialise the environment -## 1. Initialise the environment Before calling any other QuEST functions, we must [_initialise_](https://quest-kit.github.io/QuEST/group__environment.html#gab89cfc1bf94265f4503d504b02cf54d4) the QuEST [_environment_](https://quest-kit.github.io/QuEST/group__environment.html). ```cpp @@ -144,11 +149,18 @@ We can also [obtain](https://quest-kit.github.io/QuEST/group__environment.html#g QuESTEnv env = getQuESTEnv(); if (env.isGpuAccelerated) - printf("vroom vroom"); + printf("vroom vroom"); ``` -## 2. Configure the environment + +-------------------------------------------- + + + + +## Configure the environment + Configuring the environment is ordinarily not necessary, but convenient in certain applications. @@ -192,17 +204,25 @@ setInputErrorHandler(myErrorHandler); > ```cpp > #include > #include -> > void myErrorHandlerA(const char* errFunc, const char* errMsg) { > std::string func(errFunc); > std::string msg(errMsg); > throw std::runtime_error(func + ": " + msg); > } -> > setInputErrorHandler(myErrorHandler); > ``` + + + + + +-------------------------------------------- + + + + +## Create a Qureg -## 3. Create a `Qureg` To [create](https://quest-kit.github.io/QuEST/group__qureg__create.html) a statevector of `10` qubits, we call ```cpp @@ -333,7 +353,15 @@ Qureg: A density matrix `Qureg` can model classical uncertainty as results from [decoherence](https://quest-kit.github.io/QuEST/group__decoherence.html), and proves useful when simulating quantum operations on a noisy quantum computer. -## 4. Prepare an initial state + + +-------------------------------------------- + + + + +## Prepare an initial state + In lieu of manually [modifying](https://quest-kit.github.io/QuEST/group__init__amps.html) the state amplitudes, QuEST includes functions to prepare a `Qureg` in some common [initial states](https://quest-kit.github.io/QuEST/group__init__states.html) @@ -381,7 +409,14 @@ Qureg (5 qubit density matrix, 32x32 qcomps, 16.1 KiB): > The number of printed significant figures above results from our earlier calling of [`setMaxNumReportedSigFigs()`](https://quest-kit.github.io/QuEST/group__debug__reporting.html#ga15d46e5d813f70b587762814964e1994). -## 5. Apply operators + +-------------------------------------------- + + + + +## Apply operators + QuEST supports an extensive set of [operators](https://quest-kit.github.io/QuEST/group__operations.html) to effect upon a `Qureg`. ```cpp @@ -396,8 +431,13 @@ applyPhaseGadget(qureg, targets, 3, angle); > [!IMPORTANT] > Notice the type of `angle` is [`qreal`](https://quest-kit.github.io/QuEST/group__types.html#ga2d479c159621c76ca6f96abe66f2e69e) rather than the expected `double`. This is a precision agnostic alias for a floating-point, real scalar which allows you to recompile QuEST with a varying [precision](/docs/compile.md#precision) with no modifications to your code. + + + + ### controls + All unitary operations accept any number of control qubits ```cpp int controls[] = {0,1,2,3,7,8,9}; @@ -419,8 +459,13 @@ applyMultiStateControlledRotateX(qureg, controls, states, 7, target, angle); > applyMultiControlledMultiQubitNot(qureg, {0,1,2}, {4,5}); > ``` + + + + ### paulis + Some operators accept [`PauliStr`](https://quest-kit.github.io/QuEST/structPauliStr.html) which can be [constructed](https://quest-kit.github.io/QuEST/group__paulis__create.html) all sorts of ways - even inline! ```cpp applyPauliGadget(qureg, getPauliStr("XYZ"), angle); @@ -437,8 +482,15 @@ applyPauliGadget(qureg, getPauliStr("XYZ"), angle); > applyPauliY(qureg, i); > ``` + + + + ### matrices + + + #### `CompMatr1` Don't see your operation in the API? You can specify it as a general [matrix](https://quest-kit.github.io/QuEST/group__matrices.html). @@ -460,6 +512,9 @@ applyCompMatr1(qureg, target, matrix); > qcomp x = 1.5 + 3.14_i; > ``` + + + #### `CompMatr` Want a bigger matrix? No problem - they can be [any size](https://quest-kit.github.io/QuEST/group__matrices__create.html#ga634309472d1edf400174680af0685b89), with many ways to [initialise](https://quest-kit.github.io/QuEST/group__matrices__setters.html) them. @@ -489,6 +544,8 @@ syncCompMatr(bigmatrix); > This is true of any QuEST structure returned by a `create*()` function. It is _not_ true of functions prefixed with `get*()` with are always [stack variables](https://craftofcoding.wordpress.com/2015/12/07/memory-in-c-the-stack-the-heap-and-static/), hence why functions like `getCompMatr1()` can be called inline! + + #### `FullStateDiagMatr` Above, we initialised [`CompMatr`](https://quest-kit.github.io/QuEST/structCompMatr.html) to a diagonal unitary. This is incredibly wasteful; only `256` of its `65536` elements are non-zero! We should instead use [`DiagMatr`](https://quest-kit.github.io/QuEST/structDiagMatr.html) or [`FullStateDiagMatr`](https://quest-kit.github.io/QuEST/structFullStateDiagMatr.html). The latter is even distributed (if chosen by the autodeployer), permitting it to be as large as a `Qureg` itself! @@ -526,6 +583,8 @@ applyFullStateDiagMatrPower(qureg, fullmatrix, exponent); Notice the `exponent` is a `qcomp` and ergo permitted to be a complex number. Unitarity requires `exponent` is strictly real, but we can always relax the unitarity validation... + + #### validation @@ -548,8 +607,12 @@ applyCompMatr1(qureg, 0, m); ``` + + + ### circuits + QuEST includes a few convenience functions for effecting [QFT](https://quest-kit.github.io/QuEST/group__op__qft.html) and [Trotter](https://quest-kit.github.io/QuEST/group__op__paulistrsum.html) circuits. ```cpp @@ -562,9 +625,12 @@ applyTrotterizedPauliStrSumGadget(qureg, sum, time, order, reps); ``` + + ### measurements + We can also effect a wide range of non-unitary operations, such as destructive [measurements](https://quest-kit.github.io/QuEST/group__op__measurement.html) ```cpp int outcome1 = applyQubitMeasurement(qureg, 0); @@ -583,8 +649,14 @@ reportScalar("three qubit outcome", outcome2); Should we wish to leave the state unnormalised, we can instead use [projectors](https://quest-kit.github.io/QuEST/group__op__projectors.html). + + + + + ### decoherence + Density matrices created with [`createDensityQureg()`](https://quest-kit.github.io/QuEST/group__qureg__create.html#ga1470424b0836ae18b5baab210aedf5d9) can undergo [decoherence](https://quest-kit.github.io/QuEST/group__decoherence.html) channels. ```cpp @@ -637,7 +709,15 @@ multiplyDiagMatrPower(rho, fullmatrix, 0.5); ``` -## 6. Perform calculations + + +-------------------------------------------- + + + + +## Perform calculations + After so much modification to our state, we will find that its amplitudes have differed substantially. But it's impractical to observe the exponentially-many amplitudes with [`reportQureg()`](https://quest-kit.github.io/QuEST/group__qureg__report.html#ga2a9df2538e537332b1aef8596ce337b2). We can instead give QuEST the [questions](https://quest-kit.github.io/QuEST/group__calculations.html) we wish to answer about the resulting state. @@ -682,7 +762,15 @@ Qureg reduced = calcPartialTrace(qureg, targets, 3); reportScalar("entanglement", calcPurity(reduced)); ``` -## 7. Report the results + + +-------------------------------------------- + + + + +## Report the results + We've seen above that [scalars](https://quest-kit.github.io/QuEST/group__types.html) can be reported, handling the pretty formatting of real and complex numbers, controlled by settings like [`setMaxNumReportedSigFigs()`](https://quest-kit.github.io/QuEST/group__debug__reporting.html#ga15d46e5d813f70b587762814964e1994). But we can also report every data structure in the QuEST API, such as Pauli strings ```cpp @@ -725,7 +813,14 @@ CompMatr (8 qubits, 256x256 qcomps, 1 MiB): > Facilities for automatically logging to file are coming soon! -## 8. Cleanup + +-------------------------------------------- + + + + +## Cleanup + While not strictly necessary before the program ends, it is a good habit to destroy data structures as soon as you are finished with them, freeing their memory. @@ -737,7 +832,15 @@ destroyPauliStrSum(sum); destroyKrausMap(map); ``` -## 9. Finalise QuEST + + +-------------------------------------------- + + + + +## Finalise QuEST + The _final_ [step](https://quest-kit.github.io/QuEST/group__environment.html#ga428faad4d68abab20f662273fff27e39) of our program should be to call ```cpp diff --git a/docs/v4.md b/docs/v4.md index f14cca99e..db673ca79 100644 --- a/docs/v4.md +++ b/docs/v4.md @@ -16,8 +16,13 @@ QuEST `v4` has completely overhauled the API, software architecture, algorithms, > - [Acknowledgements](#acknowledgements) + + + + ## For users + - **auto-deployer**
Functions like [`createQureg()`](https://quest-kit.github.io/QuEST/group__qureg__create.html#gab3a231fba4fd34ed95a330c91fcb03b3) and [`createFullStateDiagMatr()`](https://quest-kit.github.io/QuEST/group__matrices__create.html#ga3f4b64689928ea8489a4860e3a7a530f) will _automatiaclly decide_ whether to make use of the compiled and available hardware facilities, like multithreading, GPU-acceleration and distribution. The user no longer needs to consider which deployments are optimal for their simulation sizes, nor which devices have sufficient memory to fit their `Qureg`!

@@ -46,6 +51,10 @@ QuEST `v4` has completely overhauled the API, software architecture, algorithms, The [documentation](/docs/) has been rewritten from the ground-up, and the [API doc](https://quest-kit.github.io/QuEST/topics.html) grouped into sub-categories and aesthetically overhauled with [Doxygen Awesome](https://jothepro.github.io/doxygen-awesome-css/). It is now more consistently structured, mathematically explicit, and is a treat on the eyes! + + + + ## For developers - **new build**
@@ -54,6 +63,11 @@ QuEST `v4` has completely overhauled the API, software architecture, algorithms, - **easier integration**
QuEST's backend now uses the standard `C++` [complex primitive](https://en.cppreference.com/w/cpp/numeric/complex) to represent quantum amplitudes and matrix elements, made precision agnostic via new [`qcomp`]([`qcomp`](https://quest-kit.github.io/QuEST/group__types.html#ga4971f489e74bb185b9b2672c14301983)) type. Further, [dense matrices](https://quest-kit.github.io/QuEST/structCompMatr.html) now have both 1D row-major and 2D (aliasing the 1D) memory pointers. This permits `Qureg` and matrix data to be seamlessly accessed by third-party libraries, such as for linear algebra, without the need for adapters nor expensive copying. + + + + + ## For contributors - **modular architecture**
@@ -68,6 +82,9 @@ QuEST `v4` has completely overhauled the API, software architecture, algorithms, This greatly aids the development process and helps spot bugs earlier, as well as making the assumptions more explicit and ergo the code easier to read and understand. + + + ## Acknowledgements QuEST `v4` development was lead by [Tyson Jones](https://tysonjones.io/index.html), with notable contributions from [Oliver Thomson Brown](https://www.epcc.ed.ac.uk/about-us/our-team/dr-oliver-brown), [Richard Meister](https://github.com/rrmeister), [Erich Essmann](https://www.research.ed.ac.uk/en/persons/erich-essmann), [Ali Rezaei](https://www.research.ed.ac.uk/en/persons/ali-rezaei) and [Simon C. Benjamin](https://www.materials.ox.ac.uk/peoplepages/benjamin.html). Development was financially supported by the UK National Quantum Computing centre (_NQCC200921_), the [UKRI SEEQA](https://gtr.ukri.org/projects?ref=EP%2FY004655%2F1#/tabOverview) project, the University of Oxford, and the University of Edinburgh’s Chancellor’s Fellowship scheme. Developer time was contributed by [AMD](https://www.amd.com/en.html), the [QTechTheory](https://qtechtheory.org/) group at the University of Oxford, the [EPCC](https://www.epcc.ed.ac.uk/) of the University of Edinburgh, and [Quantum Motion Technologies](https://quantummotion.tech/). Many helpful discussions were had with, and troubleshooting support given by, [NVIDIA](https://www.nvidia.com)'s [cuQuantum](https://developer.nvidia.com/cuquantum-sdk) team. From 2147c6eed326656da09b0d679b9ea863bd802965 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 22:34:38 +0200 Subject: [PATCH 22/24] testing hyperlink workaround --- docs/compile.md | 72 ++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/docs/compile.md b/docs/compile.md index e0de5a5ef..7f0de4429 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -18,24 +18,24 @@ QuEST can be compiled with [CMake](https://cmake.org/) to make a standalone exec Compiling is configured with variables supplied by the [`-D` flag](https://cmake.org/cmake/help/latest/command/add_definitions.html) to the [CMake CLI](https://cmake.org/cmake/help/latest/guide/user-interaction/index.html#command-line-cmake-tool). This page details _how_ to compile QuEST for varying purposes and hardwares. > **TOC**: -> - [Basic](#basic) -> - [Optimising](#optimising) -> - [Linking](#linking) -> - [Configuring](#configuring) -> * [Precision](#precision) -> * [Compilers](#compilers) -> * [Flags](#flags) -> - [Examples](#examples) -> - [Tests](#tests) -> * [v4](#v4) -> * [v3](#v3) -> - [Multithreading](#multithreading) -> - [GPU-acceleration](#gpu-acceleration) -> * [NVIDIA](#nvidia) -> * [AMD](#amd) -> - [cuQuantum](#cuquantum) -> - [Distribution](#distribution) -> - [Multi-GPU](#multi-gpu) +> - Basic +> - Optimising +> - Linking +> - Configuring +> * Precision +> * Compilers +> * Flags +> - Examples +> - Tests +> * v4 +> * v3 +> - Multithreading +> - GPU-acceleration +> * NVIDIA +> * AMD +> - cuQuantum +> - Distribution +> - Multi-GPU > **See also**: > - [`cmake.md`](cmake.md) for the full list of passable compiler variables. @@ -51,7 +51,7 @@ Compiling is configured with variables supplied by the [`-D` flag](https://cmake - + ## Basic @@ -102,7 +102,7 @@ How _boring_! We must pass additional arguments in order to link QuEST to our ow - + ## Optimising @@ -152,7 +152,7 @@ Read more about CMake generator configurations [here](https://cmake.org/cmake/he - + ## Linking @@ -231,13 +231,13 @@ to your project as a library! - + ## Configuring - + ### Precision @@ -268,7 +268,7 @@ The values inform types: - + ### Compilers @@ -286,7 +286,7 @@ These compilers will also be used as the _host compilers_ (around which bespoke - + ### Flags @@ -317,7 +317,7 @@ QuEST itself accepts a variety of its preprocessors (mostly related to testing) - + ## Examples @@ -340,13 +340,13 @@ as elaborated upon in [`launch.md`](launch.md#tests). - + ## Tests - + ### v4 @@ -363,7 +363,7 @@ This will compile an executable `tests` in subdirectory `build/tests/`, which ca - + ### v3 @@ -383,7 +383,7 @@ and run as explained in [`launch.md`](launch.md#v3). - + ## Multithreading @@ -419,7 +419,7 @@ The number of threads over which to parallelise QuEST's execution is chosen thro - + ## GPU-acceleration @@ -430,7 +430,7 @@ QuEST supports parallelisation using both NVIDIA GPUs (using CUDA) and AMD GPUs - + ### NVIDIA @@ -470,7 +470,7 @@ See [`launch.md`](launch.md#gpu-acceleration) for information on - + ### AMD @@ -512,7 +512,7 @@ The compiled executable can be run like any other, though the GPU behaviour can ------------------ - + ## cuQuantum @@ -550,7 +550,7 @@ No other changes are necessary, nor does cuQuantum affect [hybridising](#multi-g - + ## Distribution @@ -582,7 +582,7 @@ Note that distributed executables are launched in a distinct way to the other de - + ## Multi-GPU From 29915c134187db37479780b01539d5acd50ede55 Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 23:13:42 +0200 Subject: [PATCH 23/24] made all links agnostic to github v doxygen --- README.md | 13 +++-- docs/compile.md | 47 ++++++++++++++---- docs/compilers.md | 40 +++++++++------ docs/launch.md | 120 ++++++++++++++++++++++++++------------------- docs/tutorial.md | 70 ++++++++++++++------------ docs/v4.md | 24 ++++++--- examples/README.md | 2 + tests/main.cpp | 2 +- 8 files changed, 198 insertions(+), 120 deletions(-) diff --git a/README.md b/README.md index 78bb7832d..b577f7a39 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ > [!NOTE] -> QuEST `v4` has been released which re-designed QuEST from the ground up. Read about the exciting new features [here](/docs/v4.md). +> QuEST `v4` has been released which re-designed QuEST from the ground up. Read about the exciting new features [here](docs/v4.md). The **Quantum Exact Simulation Toolkit** (QuEST) is a high-performance simulator of quantum statevectors and density matrices. It hybridises **multithreading**, **GPU acceleration** and **distribution** to run lightning fast on laptops, desktops and @@ -83,15 +83,15 @@ In particular, QuEST `v4` was made possible through the support of the UK Nation
+ + + To learn more: -- view the [documentation](#documentation) +- view the documentation - visit the [website](https://quest.qtechtheory.org/) - read the [whitepaper](https://www.nature.com/articles/s41598-019-47174-9), which featured in Scientific Report's [Top 100 in Physics](https://www.nature.com/collections/ecehgdfcba/) :trophy: -
- -
--------------------------------- @@ -178,6 +178,9 @@ QuEST supports: --------------------------------- + + + ## 📖  Documentation > [!IMPORTANT] diff --git a/docs/compile.md b/docs/compile.md index 7f0de4429..b4a26a021 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -17,6 +17,14 @@ QuEST can be compiled with [CMake](https://cmake.org/) to make a standalone executable, or an exported library, or a library installed on the system. Compiling is configured with variables supplied by the [`-D` flag](https://cmake.org/cmake/help/latest/command/add_definitions.html) to the [CMake CLI](https://cmake.org/cmake/help/latest/guide/user-interaction/index.html#command-line-cmake-tool). This page details _how_ to compile QuEST for varying purposes and hardwares. + + + > **TOC**: > - Basic > - Optimising @@ -221,12 +229,9 @@ and the executable can thereafter be run (from within `build`) via ./myexec ``` -You can pass compiler and linker flags needed by your source files through the [`CMAKE_C_FLAGS`](https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS.html), [`CMAKE_CXX_FLAGS`](https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS.html) and [`CMAKE_EXE_LINKER_FLAGS`](https://cmake.org/cmake/help/latest/variable/CMAKE_EXE_LINKER_FLAGS.html) CMake flags as detailed in the [below section](#flags). Note however that if your configuration becomes complicated or your source code requires different `C`/`C++` standards than the QuEST source, you should consider separately compiling QuEST then linking it +You can pass compiler and linker flags needed by your source files through the [`CMAKE_C_FLAGS`](https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS.html), [`CMAKE_CXX_FLAGS`](https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS.html) and [`CMAKE_EXE_LINKER_FLAGS`](https://cmake.org/cmake/help/latest/variable/CMAKE_EXE_LINKER_FLAGS.html) CMake flags as detailed in the below section. Note however that if your configuration becomes complicated or your source code requires different `C`/`C++` standards than the QuEST source, you should consider separately compiling QuEST then linking it to your project as a library! - - - ------------------ @@ -264,8 +269,7 @@ The values inform types: > [!NOTE] -> When enabling [GPU-acceleration](#gpu-acceleration), the precision _must_ be set to `1` or `2` since GPUs do not support quad precision. - +> When enabling GPU-acceleration, the precision _must_ be set to `1` or `2` since GPUs do not support quad precision. @@ -282,7 +286,9 @@ replacing `gcc` and `g++` with e.g. [`clang`](https://clang.llvm.org/), [`cl`](h These compilers will also be used as the _host compilers_ (around which bespoke compilers _wrap_) when enabling GPU-acceleration or distribution. > [!IMPORTANT] -> It is _not_ correct to specify GPU and MPI compilers, like `nvcc` or `mpicc`, via the above flags. See the respective [GPU](#gpu-acceleration) and [MPI](#distribution) sections. +> It is _not_ correct to specify GPU and MPI compilers, like `nvcc` or `mpicc`, via the above flags. See the respective GPU and MPI sections. + + @@ -334,6 +340,8 @@ The executables will be saved in the (current) `build` directory, in a sub-direc ./examples/matrices/cpp_initialisation ``` as elaborated upon in [`launch.md`](launch.md#tests). + + ------------------ @@ -360,6 +368,8 @@ cmake .. -D ENABLE_TESTING=ON cmake --build . ``` This will compile an executable `tests` in subdirectory `build/tests/`, which can be run as explained in [`launch.md`](launch.md#tests). + + @@ -376,6 +386,7 @@ cmake .. -D ENABLE_TESTING=ON -D ENABLE_DEPRECATED_API=ON cmake --build . ``` and run as explained in [`launch.md`](launch.md#v3). + @@ -387,9 +398,11 @@ and run as explained in [`launch.md`](launch.md#v3). ## Multithreading -Multithreading allows multiple cores of a CPU, or even multiple connected CPUs, to cooperatively perform and ergo accelerate QuEST's expensive functions. Practically all modern computers have the capacity for, and benefit from, multithreading. Note it requires that the CPUs have shared memory (such as through [NUMA](https://learn.microsoft.com/en-us/windows/win32/procthread/numa-support)) and so ergo live in the same machine. CPUs on _different_ machines, connected via a network, can be parallelised over using [distribution](#distribution). +Multithreading allows multiple cores of a CPU, or even multiple connected CPUs, to cooperatively perform and ergo accelerate QuEST's expensive functions. Practically all modern computers have the capacity for, and benefit from, multithreading. Note it requires that the CPUs have shared memory (such as through [NUMA](https://learn.microsoft.com/en-us/windows/win32/procthread/numa-support)) and so ergo live in the same machine. CPUs on _different_ machines, connected via a network, can be parallelised over using distribution. QuEST uses [OpenMP](https://www.openmp.org/) to perform multithreading, so accelerating QuEST over multiple CPUs or cores requires a compiler integrated with OpenMP. This is true of almost all major compilers - see a list of tested compilers in [`compilers.md`](compilers.md#cpu). + + > [!IMPORTANT] > Using [`Clang`](https://clang.llvm.org/) on MacOS requires use of the `libomp` library, obtainable via [Homebrew](https://brew.sh/): @@ -412,6 +425,7 @@ cmake --build . This is in fact the default behaviour! The number of threads over which to parallelise QuEST's execution is chosen through setting environment variables, like [`OMP_NUM_THREADS`](https://www.openmp.org/spec-html/5.0/openmpse50.html), immediately before execution. See [`launch.md`](launch.md#multithreading) for a general guide on multithreaded deployment. + @@ -457,16 +471,22 @@ For example, compiling for the [NVIDIA A100](https://www.nvidia.com/en-us/data-c cmake .. -D ENABLE_CUDA=ON -D CMAKE_CUDA_ARCHITECTURES=80 ``` + + > [!CAUTION] > Setting the wrong compute capability will cause silently erroneous results. Always run the [unit tests](launch.md#tests) after compiling for the first time to confirm it was set correctly. + Building then proceeds as normal, e.g. ```bash # build cmake --build . --parallel ``` -See [`launch.md`](launch.md#gpu-acceleration) for information on + +The compiled executable can be run like any other, though the GPU behaviour can be prior configured with environment variables. See [`launch.md`](launch.md#gpu-acceleration) for a general guide on GPU-accelerated deployment. + + @@ -495,6 +515,8 @@ For example, compiling for the [AMD Instinct MI210 accelerator](https://www.amd. cmake .. -D ENABLE_HIP=ON -D CMAKE_HIP_ARCHITECTURES=gfx90a ``` + + > [!CAUTION] > Setting the wrong LLVM target name can cause silently erroneous results. Always run the [unit tests](launch.md#tests) after compiling for the first time to confirm it was set correctly. @@ -505,6 +527,7 @@ Building then proceeds as normal, e.g. cmake --build . --parallel ``` + The compiled executable can be run like any other, though the GPU behaviour can be prior configured with environment variables. See [`launch.md`](launch.md#gpu-acceleration) for a general guide on GPU-accelerated deployment. @@ -542,7 +565,9 @@ cmake .. -D ENABLE_CUDA=ON -D CMAKE_CUDA_ARCHITECTURES=80 -D ENABLE_CUQUANTUM=ON cmake --build . --parallel ``` -No other changes are necessary, nor does cuQuantum affect [hybridising](#multi-gpu) GPU acceleration and distribution. Launching the executable is the same as in the above section. See [`launch.md`](launch.md#gpu-acceleration). + +No other changes are necessary, nor does cuQuantum affect hybridising GPU acceleration and distribution. Launching the executable is the same as in the above section. See [`launch.md`](launch.md#gpu-acceleration). + @@ -557,6 +582,7 @@ No other changes are necessary, nor does cuQuantum affect [hybridising](#multi-g Because statevectors grow exponentially with the number of simulated qubits, it is easy to run out of memory. In such settings, we may seek to use _distribution_ whereby multiple cooperating machines on a network each store a tractable partition of the state. Distribution can also be useful to speed up our simulations, when the benefit of additional parallelisation outweighs the inter-machine communication penalties. + Enabling distribution requires compiling QuEST with an MPI compiler, such as those listed in [`compilers.md`](compilers.md#comm). Test your compiler is working via ```bash mpicxx --version @@ -574,6 +600,7 @@ cmake .. -D ENABLE_DISTRIBUTION=ON cmake --build . --parallel ``` + Note that distributed executables are launched in a distinct way to the other deployment mods, as explained in [`launch.md`](launch.md#distribution), diff --git a/docs/compilers.md b/docs/compilers.md index ef5367a3e..6c4f44303 100644 --- a/docs/compilers.md +++ b/docs/compilers.md @@ -12,15 +12,23 @@ QuEST separates compilation of the _frontend_, _backend_ and the _tests_, which This page details the specialised compilers necessary to enable specific features hardware accelerators, and lists such compilers which are known to be compatible with QuEST. + + + > **TOC**: -> - [Frontend](#frontend) -> - [Backend](#backend) -> * [comm](#comm) -> * [cpu](#cpu) -> * [gpu](#gpu) -> * [comm + gpu](#comm-gpu) -> * [gpu + cuquantum](#gpu-cuquantum) -> - [Tests](#tests) +> - Frontend +> - Backend +> * Comm +> * cpu +> * gpu +> * comm + gpu +> * gpu + cuquantum +> - Tests > **See also**: > - [`compile.md`](compile.md) for a guide to compiling QuEST. @@ -36,7 +44,7 @@ known to be compatible with QuEST. - + ## Frontend @@ -55,7 +63,7 @@ User code can be written in either `C11` or `C++14`, and has so far been tested - + ## Backend @@ -65,7 +73,7 @@ The backend is divided into subdirectories [`api/`](/quest/src/api), [`core/`](/ - + ### comm @@ -80,7 +88,7 @@ when wrapping all previously mentioned compilers. - + ### cpu @@ -92,7 +100,7 @@ have been explicitly tested, as used by the aforementioned compilers. - + ### gpu @@ -102,7 +110,7 @@ Enabling acceleration on NVIDIA or AMD GPUs requires compiling `gpu/` with a [CU - + ### comm + gpu @@ -112,7 +120,7 @@ Simultaneously emabling both distribution _and_ GPU-acceleration is possible wit - + ### gpu + cuquantum @@ -125,7 +133,7 @@ Enabling [cuQuantum](https://developer.nvidia.com/cuquantum-sdk) on NVIDIA GPUs - + ## Tests diff --git a/docs/launch.md b/docs/launch.md index e62c9bc61..447e0ff01 100644 --- a/docs/launch.md +++ b/docs/launch.md @@ -9,28 +9,39 @@ Launching your [compiled](compile.md) QuEST application can be as straightforward as running any other executable, though some additional steps are needed to make use of hardware acceleration. This page how to launch your own QuEST applications on different platforms, how to run the examples and unit tests, how to make use of multithreading, GPU-acceleration, distribution and supercomputer job schedulers, and monitor the hardware utilisation. + + + > **TOC**: -> - [Examples](#examples) -> - [Tests](#tests) -> * [v4](#v4) -> * [v3](#v3) -> - [Multithreading](#multithreading) -> * [Choosing threads](#choosing-threads) -> * [Monitoring utilisation](#monitoring-utilisation) -> * [Improving performance](#improving-performance) -> - [GPU-acceleration](#gpu-acceleration) -> * [Launching](#launching) -> * [Monitoring](#monitoring) -> * [Configuring](#configuring) -> * [Benchmarking](#benchmarking) -> - [Distribution](#distribution) -> * [Launching](#launching-1) -> * [Configuring](#configuring-1) -> * [Benchmarking](#benchmarking-1) -> - [Multi-GPU](#multi-gpu) -> - [Supercomputers](#supercomputers) -> * [SLURM](#slurm) -> * [PBS](#pbs) +> - Examples +> - Tests +> * v4 +> * v3 +> - Multithreading +> * Choosing threads +> * Monitoring utilisation +> * Improving performance +> - GPU-acceleration +> * Launching +> * Monitoring +> * Configuring +> * Benchmarking +> - Distribution +> * Launching +> * Configuring +> * Benchmarking +> - Multi-GPU +> - Supercomputers +> * SLURM +> * PBS + + + > [!NOTE] > This page assumes you are working in a `build` directory into which all executables have been compiled. @@ -41,11 +52,12 @@ Launching your [compiled](compile.md) QuEST application can be as straightforwar - + ## Examples > 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. ``` @@ -98,15 +110,15 @@ Must pass single cmd-line argument: - + ## Tests > See [`compile.md`](compile.md#tests) for instructions on compiling the `v4` and `v3` unit tests. - + - + ### v4 @@ -147,6 +159,7 @@ or specific test sections and subsections: ./tests/tests -c "validation" -c "matrix uninitialised" ``` + If the tests were compiled with [distribution enabled](compile.md#distribution), they can distributed via ```bash mpirun -np 8 ./tests/tests @@ -182,10 +195,11 @@ Alas tests launched in this way cannot be deployed with distribution. - + ### v3 + The deprecated tests, when [compiled](compile.md#v3), can be run from the `build` directory via ```bash ./tests/deprecated/dep_tests @@ -211,17 +225,18 @@ ctest - + ## Multithreading > [!NOTE] > Parallelising QuEST over multiple cores and CPUs requires first compiling with > multithreading enabled, as detailed in [`compile.md`](compile.md#multithreading). + - + ### Choosing threads @@ -245,12 +260,13 @@ It is prudent to choose as many threads as your CPU(s) have total hardware threa > [!NOTE] -> When running [distributed](#distribution), variable `OMP_NUM_THREADS` specifies the number of threads _per node_ and so should ordinarily be the number of hardware threads (or cores) _per machine_. +> When running distributed, variable `OMP_NUM_THREADS` specifies the number of threads _per node_ and so should ordinarily be the number of hardware threads (or cores) _per machine_. + - + ### Monitoring utilisation @@ -282,7 +298,7 @@ Usage of multithreading can be (inadvisably) forced using [`createForcedQureg()` - + ### Improving performance @@ -314,7 +330,7 @@ and never specifies [`schedule`](https://rookiehpc.org/openmp/docs/schedule/inde > [!TIP] -> Sometimes the memory bandwidth between different sockets of a machine is poor, and it is substantially better to exchange memory in bulk between their NUMA nodes, rather than through repeated random access. In such settings, it can be worthwhile to hybridise multithreading and distribution, even upon a single machine, partitioning same-socket threads into their own MPI node. This forces inter-socket communication to happen in-batch, via message-passing, at the expense of using _double_ total memory (to store buffers). See the [distributed](#distribution) section. +> Sometimes the memory bandwidth between different sockets of a machine is poor, and it is substantially better to exchange memory in bulk between their NUMA nodes, rather than through repeated random access. In such settings, it can be worthwhile to hybridise multithreading and distribution, even upon a single machine, partitioning same-socket threads into their own MPI node. This forces inter-socket communication to happen in-batch, via message-passing, at the expense of using _double_ total memory (to store buffers). See the distributed section. @@ -322,17 +338,17 @@ and never specifies [`schedule`](https://rookiehpc.org/openmp/docs/schedule/inde - + ## GPU-acceleration > [!NOTE] > Using GPU-acceleration requires first compiling QuEST with `CUDA` or `HIP` enabled (to utilise NVIDIA and AMD GPUs respectively) as detailed in [`compile.md`](compile.md#gpu-acceleration). - + - + ### Launching @@ -341,12 +357,13 @@ The compiled executable is launched like any other, via ./myexec ``` -Using _multiple_ available GPUs, regardless of whether they are local or distributed, is done through additionally enabling [distribution](#multi-gpu). +Using _multiple_ available GPUs, regardless of whether they are local or distributed, is done through additionally enabling distribution. + - + ### Monitoring @@ -390,7 +407,7 @@ Usage of GPU-acceleration can be (inadvisably) forced using [`createForcedQureg( - + ### Configuring @@ -404,7 +421,7 @@ There are a plethora of [environment variables](https://askubuntu.com/questions/ - + ### Benchmarking @@ -419,7 +436,7 @@ However, it _does_ mean codes which seeks to benchmark QuEST must be careful to - + ## Distribution @@ -427,14 +444,15 @@ However, it _does_ mean codes which seeks to benchmark QuEST must be careful to > [!NOTE] > Distributing QuEST over multiple machines requires first compiling with > distribution enabled, as detailed in [`compile.md`](compile.md#distribution). + > [!IMPORTANT] -> Simultaneously using distribution _and_ GPU-acceleration introduces additional considerations detailed in the [proceeding section](#multi-gpu). +> Simultaneously using distribution _and_ GPU-acceleration introduces additional considerations detailed in the proceeding section. - + ### Launching @@ -447,17 +465,18 @@ or on some platforms (such as with Intel and Microsoft MPI): mpiexec -n 32 myexec.exe ``` -Some supercomputing facilities however may require custom or additional commands, like [SLURM](https://slurm.schedmd.com/documentation.html)'s [`srun`](https://slurm.schedmd.com/srun.html) command. See an excellent guide [here](https://docs.lumi-supercomputer.eu/runjobs/scheduled-jobs/distribution-binding/#distribution), and the job submission guide [below](#supercomputers). +Some supercomputing facilities however may require custom or additional commands, like [SLURM](https://slurm.schedmd.com/documentation.html)'s [`srun`](https://slurm.schedmd.com/srun.html) command. See an excellent guide [here](https://docs.lumi-supercomputer.eu/runjobs/scheduled-jobs/distribution-binding/#distribution), and the job submission guide below. ```bash srun --nodes=8 --ntasks-per-node=4 --distribution=block:block ``` + > [!IMPORTANT] > QuEST can only be distributed with a _power of `2`_ number of nodes, i.e. `1`, `2`, `4`, `8`, `16`, ... > [!NOTE] -> When [multithreading](#multithreading) is also enabled, the environment variable `OMP_NUM_THREADS` +> When multithreading is also enabled, the environment variable `OMP_NUM_THREADS` > will determine how many threads are used by _each node_ (i.e. each MPI process). Ergo optimally > deploying to `8` machines, each with `64` CPUs (a total of `512` CPUs), might resemble: > ```bash @@ -465,6 +484,7 @@ srun --nodes=8 --ntasks-per-node=4 --distribution=block:block > ``` + It is sometimes convenient (mostly for testing) to deploy QuEST across more nodes than there are available machines and sockets, inducing a gratuitous slowdown. Some MPI compilers like [OpenMPI](https://www.open-mpi.org/) forbid this by default, requiring additional commands to permit [oversubscription](https://docs.open-mpi.org/en/main/launching-apps/scheduling.html). ```bash mpirun -np 1024 --oversubscribe ./mytests @@ -472,7 +492,7 @@ mpirun -np 1024 --oversubscribe ./mytests - + ### Configuring @@ -482,7 +502,7 @@ mpirun -np 1024 --oversubscribe ./mytests - + ### Benchmarking @@ -499,7 +519,7 @@ It is ergo always prudent to explicitly call [`syncQuESTEnv()`](https://quest-ki - + ## Multi-GPU @@ -529,7 +549,7 @@ It is ergo always prudent to explicitly call [`syncQuESTEnv()`](https://quest-ki - + ## Supercomputers @@ -544,7 +564,7 @@ For convenience however, we offer some example [SLURM](https://slurm.schedmd.com - + ### SLURM @@ -579,7 +599,7 @@ srun ./myexec - + ### PBS diff --git a/docs/tutorial.md b/docs/tutorial.md index fc4379cb7..68b3fbf1b 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -12,6 +12,7 @@ QuEST is included into a `C` or `C++` project via #include "quest.h" ``` + > [!TIP] > Some of QuEST's deprecated `v3` API can be accessed by specifying `ENABLE_DEPRECATED_API` when [compiling](/docs/compile.md#v3), or defining it before import, i.e. > ```cpp @@ -34,28 +35,36 @@ Simulation typically proceeds as: Of course, the procedure is limited only by the programmers imagination `¯\_(ツ)_/¯` Let's see an example of these steps below. + + > **TOC**: -> - [Initialise the environment](#initialise-the-environment) -> - [Configure the environment](#configure-the-environment) -> - [Create a `Qureg`](#create-a-qureg) -> - [Prepare an initial state](#prepare-an-initial-state) -> - [Apply operators](#apply-operators) -> * [controls](#controls) -> * [paulis](#paulis) -> * [matrices](#matrices) -> * [circuits](#circuits) -> * [measurements](#measurements) -> * [decoherence](#decoherence) -> - [Perform calculations](#perform-calculations) -> - [Report the results](#report-the-results) -> - [Cleanup](#cleanup) -> - [Finalise QuEST](#finalise-quest) +> - Initialise the environment +> - Configure the environment +> - Create a `Qureg` +> - Prepare an initial state +> - Apply operators +> * controls +> * paulis +> * matrices +> * circuits +> * measurements +> * decoherence +> - Perform calculations +> - Report the results +> - Cleanup +> - Finalise QuEST + -------------------------------------------- - + ## Initialise the environment @@ -157,7 +166,7 @@ if (env.isGpuAccelerated) -------------------------------------------- - + ## Configure the environment @@ -219,7 +228,7 @@ setInputErrorHandler(myErrorHandler); -------------------------------------------- - + ## Create a Qureg @@ -358,7 +367,7 @@ A density matrix `Qureg` can model classical uncertainty as results from [decohe -------------------------------------------- - + ## Prepare an initial state @@ -413,7 +422,7 @@ Qureg (5 qubit density matrix, 32x32 qcomps, 16.1 KiB): -------------------------------------------- - + ## Apply operators @@ -430,10 +439,11 @@ applyPhaseGadget(qureg, targets, 3, angle); > [!IMPORTANT] > Notice the type of `angle` is [`qreal`](https://quest-kit.github.io/QuEST/group__types.html#ga2d479c159621c76ca6f96abe66f2e69e) rather than the expected `double`. This is a precision agnostic alias for a floating-point, real scalar which allows you to recompile QuEST with a varying [precision](/docs/compile.md#precision) with no modifications to your code. + - + ### controls @@ -461,7 +471,7 @@ applyMultiStateControlledRotateX(qureg, controls, states, 7, target, angle); - + ### paulis @@ -484,7 +494,7 @@ applyPauliGadget(qureg, getPauliStr("XYZ"), angle); - + ### matrices @@ -608,7 +618,7 @@ applyCompMatr1(qureg, 0, m); - + ### circuits @@ -626,7 +636,7 @@ applyTrotterizedPauliStrSumGadget(qureg, sum, time, order, reps); - + ### measurements @@ -652,7 +662,7 @@ Should we wish to leave the state unnormalised, we can instead use [projectors]( - + ### decoherence @@ -714,7 +724,7 @@ multiplyDiagMatrPower(rho, fullmatrix, 0.5); -------------------------------------------- - + ## Perform calculations @@ -767,7 +777,7 @@ reportScalar("entanglement", calcPurity(reduced)); -------------------------------------------- - + ## Report the results @@ -817,7 +827,7 @@ CompMatr (8 qubits, 256x256 qcomps, 1 MiB): -------------------------------------------- - + ## Cleanup @@ -837,7 +847,7 @@ destroyKrausMap(map); -------------------------------------------- - + ## Finalise QuEST diff --git a/docs/v4.md b/docs/v4.md index db673ca79..bc8018355 100644 --- a/docs/v4.md +++ b/docs/v4.md @@ -9,16 +9,24 @@ QuEST `v4` has completely overhauled the API, software architecture, algorithms, implementations and testing. This page details the new features, divided into those relevant to _users_, _developers_ who integrate QuEST into larger software stacks, and _contributors_ who develop QuEST or otherwise peep at the source code! + + + > **TOC**: -> - [For users](#for-users) -> - [For developers](#for-developers) -> - [For contributors](#for-contributors) -> - [Acknowledgements](#acknowledgements) +> - For users +> - For developers +> - For contributors +> - Acknowledgements - + ## For users @@ -53,7 +61,7 @@ QuEST `v4` has completely overhauled the API, software architecture, algorithms, - + ## For developers @@ -66,7 +74,7 @@ QuEST `v4` has completely overhauled the API, software architecture, algorithms, - + ## For contributors @@ -83,7 +91,7 @@ QuEST `v4` has completely overhauled the API, software architecture, algorithms, - + ## Acknowledgements diff --git a/examples/README.md b/examples/README.md index 08e536881..7fe49d61c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -8,3 +8,5 @@ --> 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. + diff --git a/tests/main.cpp b/tests/main.cpp index 8648cf446..190b58ef1 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -3,7 +3,7 @@ * * @author Tyson Jones * - * @defgroup tests 🔧 Tests + * @defgroup tests 🧪 Tests * * @defgroup testutils Utilities * @ingroup tests From 4df61b401b90c17fa0b95be70c06521846c9433f Mon Sep 17 00:00:00 2001 From: Tyson Jones Date: Sun, 6 Apr 2025 23:47:51 +0200 Subject: [PATCH 24/24] added top-level API and tests doxygen doc but only a link, since it's apparently impossible to move up the group summary pages. Grr! --- docs/README.md | 1 + quest/include/quest.h | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/docs/README.md b/docs/README.md index a3845c33d..4bf0ea018 100644 --- a/docs/README.md +++ b/docs/README.md @@ -34,6 +34,7 @@ Interested in contributing? Then check out: Want to learn how what's under the hood? Read the - 🏆  [whitepaper](https://www.nature.com/articles/s41598-019-47174-9) which featured in Scientific Report's [Top 100 in Physics](https://www.nature.com/collections/ecehgdfcba/) - 📝  [preprint](https://arxiv.org/abs/2311.01512) which derives `v4`'s optimised algorithms. +- 🧪  [tests](/tests) which compare QuEST's outputs to non-optimised calculations. - 📈  [benchmarks](https://www.youtube.com/watch?v=dQw4w9WgXcQ) which are coming soon! diff --git a/quest/include/quest.h b/quest/include/quest.h index a9e1632e5..e3fde6756 100644 --- a/quest/include/quest.h +++ b/quest/include/quest.h @@ -11,6 +11,21 @@ * @defgroup api 📋 API */ +/** + * @page apilink 📋 API + * The API documentation can be viewed at @ref api. + * + * We're working hard to move that page up one level. 😎 + */ + +/** + * @page testlink 🧪 Tests + * + * The unit and integration tests can be viewed at @ref tests. + * + * We're working hard to move that page up one level. 😎 + */ + #ifndef QUEST_H #define QUEST_H