quest_bind
A wrapper around QuEST v3.5.0.
Quantum Exact Simulation Toolkit (QuEST) is a no-fluff, bent-on-speed quantum circuit simulator [1]. It is distributed under MIT License.
How to use it
Initialize a new binary crate:
Add quest_bind
to your project's dependencies:
Now write some code and put it in ./src/main.rs
:
use *;
The documentation is available online, as well as locally:
Lastly, compile and run the program:
You should be able to see something like:
EXECUTION ENVIRONMENT:
Running locally on one node
Number of ranks is 1
OpenMP enabled
Number of threads available is 8
Precision: size of qreal is 8 bytes
QUBITS:
Number of qubits is 2.
Number of amps is 4.
Number of amps per rank is 4.
---
Prepare Bell state: |00> + |11>
Qubit "0" measured in state: |0>
Qubit "1" measured in state: |0>
They match!
Distributed and GPU-accelerated mode
QuEST support for MPI and GPU-accelerated computation ca be enabled in
quest_bind
by setting appropriate feature flags. To enable QuEST's MPI mode,
set the mpi
feature for quest_bind
. Simply edit Cargo.toml
of your binary
crate:
[]
= "tryme"
= "0.1.0"
= "2021"
[]
= { = ["mpi"] }
Now if you compile and run the above program again, the output should be:
EXECUTION ENVIRONMENT:
Running distributed (MPI) version
Number of ranks is 1
...
The feature "gpu"
enables the GPU-accelerated mode. These two features are
mutually exclusive and in case both flags are set, the feature "mpi"
takes
precedence.
Testing
To run unit tests for this library, first clone the repository together with QuEST source code as submodule:
Then run:
Note that quest_bind
will not run QuEST
's test suite, nor will it check
QuEST
's correctness. The tests here are intended to check if the C API is
invoked correctly, and if Rust's types are passed safely back and forth across
the FFI boundary.
If you want to run the test suite in the single-precision floating point mode,
make sure the build script recompiles libQuEST.so
with the right type
definitions:
By defualt, quest_bind
uses Rust's double precision floating-point type:
f64
. See Numercal types section below.
You can also try the available examples by running, e.g.:
To see the list of all available examples, try:
Note on performance
In the typical case when it's the numerical computation that dominates the CPU
usage, and not API calls, there should be no discernible difference in
performance between programs calling QuEST routines directly and analogous
applications using quest_bind
. Remember, however, to enable optimizations for
both quest_bind
and QuEST
by compiling your code using the "release"
profile:
Handling exceptions
On failure, QuEST throws exceptions via user-configurable global
invalidQuESTInputError()
.
By default, this function prints an error message and aborts, which is
problematic in a large distributed setup.
We opt for catching all exceptions early by reimplementing
invalidQuESTInputError()
to unwind the stack using Rust's
panic
mechanism.
Additionally, all error messages reported by QuEST are logged as errors. To be able to see them, add a logger as a dependency to your crate, e.g.:
Then enable logging in your application:
and run:
RUST_LOG=info
See log
crate for more on logging in Rust.
The type QuestError
doesn't contain (possibly malformed) data returned by the
API call on failure. Only successful calls can reach the library user. This is
intentional, following guidelines from the QuEST documentation:
[Upon failure] Users must ensure that the triggered API call does not continue (e.g. the user exits or throws an exception), else QuEST will continue with the valid [sic!] input and likely trigger a seg-fault.
See Quest API for more information.
Numerical types
For now, numerical types used by quest_bind
match exactly the C types that
QuEST uses on x86_64
. This is a safe, but not very portable strategy. We pass
Rust types directly to QuEST without casting, assuming the following type
definitions:
pub type c_float = f32;
pub type c_double = f64;
pub type c_int = i32;
pub type c_longlong = i64;
pub type c_ulong = u64;
This should work for many different architectures. If your system uses slightly
different numerical types, quest_bind
simply won't compile and there is not
much you can do besides manually altering the source code.
To check what C types are defined by your Rust installation, see the local
documentation for the module std::ffi
in Rust's Standard Library:
Contributing
Here's a few things to know, if you'd like to contribute to quest_bind
.
-
The Rust codebase is formatted according to the settings in
./rustfmt.toml
. We enable some unstable features ofrustfmt
. To format your patches correctly, you will need the nightly version of the Rust compiler. Before opening a pull request, remove lint from the code by running: