Releases: QuEST-Kit/QuEST
v4.1.0
Overview
This minor release (#622) adds some convenience functions to control QuEST's reporter functions, patches a critical segmentation fault in simulation above 32 qubits, patches the build's installation process and some minor reporter issues, and improves the documentation.
New features
Two new Debug > Reporting
functions customise the outputs of functions like reportPauliStr()
and reportPauliStrSum()
:
setReportedPauliChars()
specifies new output characters to replace"IXYZ"
.setReportedPauliStrStyle()
sets whether to printPauliStr
as"XYIIIZ"
or"Z0 Y4 X5"
.
Patches
- #623 patched a critical bug in the amplitude-enumeration logic which caused a segmentation fault for simulations of over 32 qubits (believed to cause #618).
- 15a08ae removed superfluous re-validation of user input inside Trotter circuits.
- 5e449fe patched a seg-fault when calling
setMaxNumReportedItems(1,1)
(though insignificant bug #588 remains). - fb2527e patched
reportScalar()
which previously ignored the number of sig-figs set withsetMaxNumReportedSigFigs()
. - c92ebb3 patched invalid-input error messages that interrupt reports which do not end in a trailing newline (by now always printing a newline before the error message).
- #624 restored C++17 compatibility of the source (by removing non-standard designated initialisers), which is now targeted by the build (though unit tests still require C++20).
- #601 and #616 patched the build's
install
process which previously required users to gratuitously re-specify preprocessor macros (likeCOMPILE_MPI
) when including the pre-installed QuEST header. - 420e11d ensures that changes to the
devel
branch will trigger CI tests (as intended).
Other changes
- Examples have been restructured, and a new example using QuEST to perform real-time Hamiltonian simulation (
dynamics.c(pp)
) was added. - CI now runs Windows tests first since they are the most error-prone.
- CI now runs all
isolated
examples (in addition to merely compiling them), testing for link-time issues (see e9fa519). - CI now compiles and runs all files in the new
automated
examples folder, offering external contributors a quick and easy way to platform-agnostically test their PR (in lieu of preparing a unit test)(see e9fa519). - Code-coverage reporting in PRs (using LCOV) was disabled since it did not capture accelerated backend coverage.
- Many functions received new documentation (although the war continues).
- Several custom Doxygen tags were renamed (see #621)
New contributors
This release contained patches from new contributors:
- Luc Jaulmes in #616
- James Richings in #623
v4.0.0
🎉 What's new
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
-
auto-deployer
Functions likecreateQureg()
andcreateFullStateDiagMatr()
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 theirQureg
! -
new deployments
QuEST can now make use of multiple GPUs, distributed across different machines on a network, or tightly-coupled by a high-bandwidth interconnect (like NVLink); or both! This is true independent of whether you're also using cuQuantum, NVIDIA or AMD GPUs. Further, used deployments are heterogeneous; simultaneousQureg
s may use different facilities at runtime! -
much faster
Practically all backend algorithms have been replaced with novel, optimised, bespoke routines - primarily documented in arXiv 2311.0512. Further, special care has been paid to enabling compile-time optimisations, giving structures (like matrices) persistent GPU memory, and lazily evaluating properties like matrix unitarity only once! -
cleaner interface
The API has been polished; function names are more consistent, accept an arithmetic-overloaded complex scalar type (calledqcomp
), and more natural data structures. Matrices, Pauli tensors and their weighted sums are now easier to initialise and populate, accepting even matrix and string literals!
Some functions now have type overloads - even theC
ones! - and additionalC++
overloads accepting native containers likestd::vector
. -
reporters
The API also includes utilities for prettily printing all QuEST data structures (like states, operators and scalars) and reporting on the environment and Qureg hardware accelerations being used, the memory available, and the maximum possible simulation sizes.
Input validation has also been massively broadened and error messages made precise and dynamic. Usability is through the roof! -
new functions
The set of supported quantum operations has greatly expanded. All unitaries can be effected with any number of control qubits (in any state), diagonal matrices can be raised to powers, density matrices can undergo partial tracing and inhomogeneous Pauli channels (in addition to general Kraus maps and superoperatos), and multi-qubit projectors can now be performed, with and without renormalisation. -
more control
Extensive new debugging facilities allow disabling or changing the validation precision and error response at runtime, and controlling how many amplitudes and significant figures ofQureg
and matrices are printed. -
better documentation
The documentation has been rewritten from the ground-up, and the API doc grouped into sub-categories and aesthetically overhauled with Doxygen Awesome. It is now more consistently structured, mathematically explicit, and is a treat on the eyes!
For developers
-
new build
The CMake build has been overhauled and modernised, with wider platform support and facilities to ease QuEST's integration into larger stacks. The build is more modular, limiting specialised compilers (likenvcc
andmpicc
) to compiling only their essential files. This minimises friction and widens QuEST's compiler support. -
easier integration
QuEST's backend now uses the standardC++
complex primitive to represent quantum amplitudes and matrix elements, made precision agnostic via newqcomp
type. Further, dense matrices now have both 1D row-major and 2D (aliasing the 1D) memory pointers. This permitsQureg
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
QuEST's new software architecture is highly modular, separating the responsibilities of interfacing, validating user input, core pre-processing, localising distributed data, choosing which accelerator to use (CPUs or GPUs), and modifying local data using an accelerator. The core pre-processing is further modularised into modules responsible for autodeploying, inlining, performing maths and bitwise routines, probing available memory, checking internal preconditions, parsing user text, printing output, managing data structures and generating random numbers.
Seearchitecture.md
for more information. -
C++
backend
While QuEST's frontend remainsC
andC++
agnostic, the backend has become consistentlyC++17
, affording development luxuries like overloading, templating, type inference, namespaces, smart pointers, constant expressions, type-traiting, structured bindings, range-based looping and use of standard lists likevector
. We have however endeavoured to keep the use ofC++
facilities simple so that the code remains readable and editable byC
programmers. -
internal preconditions
QuEST's defensive design has massively improved by the extensive use of precondition checks, which cheaply validate that internal functions receive correct inputs, where there is room for insidious bugs or future changes.
This...
v3.7.0
Overview
This release integrates a cuQuantum backend (generously supported by the NQCC), optimises distributed communication, and improves the unit tests.
New features
- QuEST gained a new backend which integrates cuQuantum and Thrust for optimised simulation on modern NVIDIA GPUs. This is compiled with cmake argument
-DUSE_CUQUANTUM=1
, as detailed in the compile doc. Unlike QuEST's other backends, this does require prior installation of cuQuantum, outlined here. This deployment mode should run much faster than QuEST's custom GPU backend, and will soon enable multi-GPU simulation. The entirety of QuEST's API is supported! 🎉
This work was supported by the UK National Quantum Computing centre [NQCC200921]
Other changes
- QuEST's distributed communication has been optimised when exchanging states via many maximum-size messages, thanks to the work of Jakub Adamski as per this manuscript.
- Functions like
multiQubitUnitary()
andmixMultiQubitKrausMap()
have relaxed the precision of their unitarity and CPTP checks, so they will complain less about user matrices. Now, for example, a unitarity matrixU
is deemed valid only if every element ofU*dagger(U)
has a Euclidean distance of at mostREAL_EPS
from its expected identity-matrix element. - Unit tests now check that their initial register states are as expected before testing an operator. This ensures that some tests do not accidentally pass when they should be failing (like when run with an incorrectly specified GPU compute capability) due to an unexpected all-zero initial state.
- Unit tests now use an improved and numerically stable function for generating random unitaries and Kraus maps, so should trigger fewer precision errors and false test failures.
v3.6.0
Overview
This release makes QuEST compatible with AMD GPUs 🎉, makes the unit tests compatible with MSVC on Windows, and adds sub-diagonal operators.
New features
- Compatibility with AMD GPUs, thanks to @bvillasen!
SubDiagonalOp
; a non-distributed structure representing a diagonal unitary (specified only through the diagonal elements) upon a subset of a qureg's qubits. This can be passed to new functions:createSubDiagonalOp()
destroySubDiagonalOp()
diagonalUnitary()
applySubDiagonalOp()
applyGateSubDiagonalOp()
- Functions for applying gates specified as non-unitary matrices. Specifically:
applyGateMatrixN()
applyMultiControlledGateMatrixN()
setQuregToPauliHamil()
for casting a Pauli Hamiltonian into a dense Z-basis matrix, stored in a density matrixQureg
.- Phase function
SCALED_INVERSE_SHIFTED_WEIGHTED_DISTANCE
recognised byapplyParamNamedPhaseFunc()
(and related functions)
Other changes
- Unit tests are now compatible with MSVC on Windows, and are automatically ran from Github Actions.
- Documentation is automatically regenerated whenever the master branch is updated.
Bug fixes
- Math functions used internally (like
cos()
) now explicitly use quad precision when compiled withPRECISION=4
, thanks to @Milos9304 - Fixed overflow and other precision issues in the unit tests, thanks to @rrmeister
v3.5.0
Overview
This release adds some quality-of-life functions, mostly to the benefit of larger software stacks which integrate QuEST. It also includes some bug patches and internal software architectural clean-ups, primarily by @rrmeister.
New features
setDensityAmps()
allowing direct modification of the amplitudes of a density matrix.copySubstateToGPU()
allowing partial overwriting of a statevector in GPU memorycopySubstateFromGPU()
allowing partial loading of a GPU statevector into accessible memorymixNonTPKrausMap()
to simulate Kraus maps which are not necessarily trace-preserving
Other changes
- Updated the Bernstein-Vazirani demo to simulate more analogously to the experimental method
- Updated demo codes to use precision-agnostic string formatters
- Improved CMake build (f8747ca)
- Improved the internal validation architecture
Bug fixes
- patched rare distributed bug in
calcTotalProb()
of density matrices (#326) - patched rare GPU build bug in
applyPhaseFunc()
- patched rare memory leak during failed validation of
Qureg
andDiagonalOp
validation - patched GPU build flags (512966a)
- patched
invalidQuESTInputError()
build problem on Windows (#314) - patched build warnings related to precision of internal non-simulation functions (fc25c34)
v3.4.1
Overview
This is a quick patch of a GPU build bug, and a logical error in an unimportant GPU edge-case.
Bug fixes
- patched CUDA build of v3.4.0.
- patched edge-case of
calcProbOfOutcome
which on GPU with a state-vector of a single qubit, always returned 1.
v3.4.0
Overview
This release refactors QuEST for native Windows support, and adds some initialisation and seeding utilities mostly useful for simulators which use QuEST as a backend.
New features
Deterministically project a qubit into a classical outcome without renormalising the state.
applyProjector()
Density matrices, like state-vectors, can now be directly initialised from arrays of all amplitudes.
initStateFromAmps()
Users can now view and keep track of the seeds to QuEST's random number generator.
getQuESTSeeds()
Native Windows support! QuEST can now be compiled directly in MSVC, without needing to use MinGW. An MSVC build test is now part of the Github CI, although unit tests do not yet run automatically.
- compile with CMake and NMake in the
build
folder viacmake .. -G "NMake Makefiles" nmake
- or, compile directly with GNUMake from the root directory via
cp examples/makefile . make COMPILER=cc COMPILER_TYPE=MSVC
API breaking changes
seedQuEST()
andseedQuESTDefault()
now require a pointer to the activeQuESTEnv
instance.- Previously,
SCALED_INVERSE_SHIFTED_DISTANCE
inapplyNamedPhaseFunc()
computedcoeff/sqrt( (x2-x1-dx)^2 + ... )
, but now computescoeff/sqrt( (x1-x2-dx)^2 + ...
(x1
andx2
have swapped), to be more in-line with the expected behaviour. - Previously,
SCALED_INVERSE_SHIFTED_NORM
andSCALED_INVERSE_SHIFTED_DISTANCE
inapplyNamedPhaseFunc()
used their divergence parameter when their denominators were precisely zero. Now, the divergence parameter is used whenever the denominator is withinREAL_EPS
to zero. This catches the scenario when a divergence has been translated only a very small distance from a sampled point.
v3.3.0
Overview
This release adds some powerful new operators including pauli gadgets with any number of control qubits, diagonal operators expressed as general exponential-polynomial phase functions, and optimised implementations of the quantum Fourier transform and multi-controlled multi-target X gates. It brings the ability to efficiently calculate batches of probabilities of arbitrary quantum substates, and functions for creating diagonal operators from Ising Hamiltonians. These utilities are useful for high-performance simulation of quantum chemistry algorithms. Finally, we add an example implementation of Grover's algorithm, and the documentation is given a welcome face-lift.
New features
In addition to calcProbOfOutcome
for calculating the probability of a single qubit outcome, one can now efficiently obtain the entire set of probabilities for the classical outcomes of entire sub-registers.
calcProbOfAllOutcomes()
Added optimised algorithmic methods for simultaneously applying multiple Pauli X gates. These run as fast as a single invocation of pauliX()
, even in distributed mode!
multiQubitNot()
multiControlledMultiQubitNot()
.
With the help of Milos Prokop, Ising Hamiltonians expressed in the Pauli basis can now be loaded directly into diagonal operators, for much faster simulation.
initDiagonalOpFromPauliHamil()
createDiagonalOpFromPauliHamilFile()
Added controlled versions of the existing phase gadgets and Pauli gadgets.
multiControlledMultiRotateZ()
multiControlledMultiRotatePauli()
Added an efficient implementation of the quantum Fourier transform (QFT), which can be applied to both state-vectors and density-matrices, on an arbitrary sub-register.
applyQFT()
applyFullQFT()
With the help of Richard Meister, diagonal unitaries can be applied directly to a state, specified as a phase function, and requiring no dedicated memory. This includes phase functions specified as one-dimensional exponential-polynomials...
applyPhaseFunc()
applyPhaseFuncOverrides()
or as multi-variable exponential-polynomials...
applyMultiVarPhaseFunc()
applyMultiVarPhaseFuncOverrides()
or as one of many named phase functions, including several useful for quantum chemistry simulations, like measures of distance between registers representing signed integers in two's complement!
applyNamedPhaseFunc()
applyNamedPhaseFuncOverrides()
applyParamNamedPhaseFunc()
applyParamNamedPhaseFuncOverrides()
Finally, some changes to documentation.
- updated the tutorial (
examples/README.md
) with extensive compilation and testing guidance - added example implementation of Grover's search
createQureg
andcreateDensityQureg
now include extensive documentation about their memory patterns on all hardware backends- added doc for
QuEST_PREC
,ComplexMatrix2
andComplexMatrix4
- added 'see more' sections to most functions, linking to related functions
- linked all doc to
invalidQuESTInputError()
, if thrown - function exceptions are now formatted cleanly in lists
- code snippets now use syntax highlighting
- removed ugly borders around circuit diagrams
Bug fixes
- patched
syncDiagonalOp
which previously did not copy all of a state-vector into GPU memory - supressed CMake build warnings (by Gleb Struchalin)
- fixed doc rendering issue (via regrettable js/html hacks)
- fixed all doxygen warnings
- patched unit tests to compile precision agnostically
- patched QASM output to compile precision agnostically
- patched distributed file IO unit tests (like
createPauliHamilFromFile
), which sometimes seg-faulted
v3.2.1
Overview
A minor patch to the QuEST build.
Changes
getEnvironmentString()
now returns a standard format between the serial, multithreaded, distributed, and GPU-accelerated backends. This enables convenient parsing by interfacing projects, like pyQuEST.
Bug fixes
- removed unnecessary check for OpenMP compilers in non-multithreaded mode (by external contributor, Christopher Andrews @chr5tphr)
v3.2.0
Overview
This release adds a new encapsulation for representing Hamiltonians in the Pauli basis, adds efficient representation of diagonal operators, adds continuous time simulation through Trotter-Suzuki decompositions, and enables multiplying arbitrary complex matrices directly onto quantum states.
New features
Added a new type, PauliHamil
, representing a weighted sum of Pauli strings; a common basis for representing Hamiltonians.
createPauliHamil()
createPauliHamilFromFile()
initPauliHamil()
destroyPauliHamil()
reportPauliHamil()
applyPauliHamil()
calcExpecPauliHamil()
Added the ability to generate Trotter circuits, including higher order 'symmetrized' Suzuki decompositions. This can be used to unitarily evolve a state in time, under a given PauliHamil
. The gates prescribed by the decomposition can be captured with QASM logging.
applyTrotterCircuit()
Added a new type, DiagonalOp
, which can represent non-unitary and even non-Hermitian diagonal operators acting on the full Hilbert space. The data for this operator is distributed, and persists in GPU memory, for rapid simulation.
createDiagonalOp()
destroyDiagonalOp()
initDiagonalOp()
syncDiagonalOp()
applyDiagonalOp()
calcExpecDiagonalOp()
Added support for directly multiplying arbitrary complex matrices onto a state-vector or density-matrix.
applyMatrix2()
applyMatrix4()
applyMatrixN()
applyMultiControlledMatrixN()
Bug fixes
- fixed OpenMP linking on MacOS (by external contributor, Drew Silcock @drewsilcock)
- fixed CUDA compiling with CMake (by external contributor, @SachinCompton)
- fixed multithreading with gcc-9 (with help from external contributor, Zach van Rijn @zv-io)
- tweaked unit testing precision tolerances