This section contains miscellaneous functions and classes that are used in the implementation of the simulator

Random numbers

Random numbers are used in several contexts in the simulator. Firstly, quantum measurement simulation requires generation of random numbers to determine whether to pick one outcome or another. Secondly, benchmarking and verification functions generate random samples on which to test the simulator.

The Random class is used in the Qubits object to generate the random numbers necessary for simulating measurements.

template<std::floating_point Fp = double>
class qsl::Random

A small class for generating random numbers.

This class is a wrapper around a pseudo-random number generator. Once the class has been constructed, use the getNum() member function to get a uniform random number in a range specified in the constructor.

The implementation uses the Mersenne-Twister algorithm with n=19937 (called mt19937), which passes enough statistical tests for randomness that it is legitimate to use it in scientific software.

std::default_random_engine is not a good choice because it is designed for “relatively casual, inexpert and/or

lightweight use” (C++ std library documentation).

Public Functions

Random(Fp a, Fp b)

Construct the class and specify the range.

Constructs a Random object which can be used to get uniform random numbers in the range [a,b).

Parameters
  • a – The bottom end of the range

  • b – The top end of the range

Fp getNum()

Get a uniform random number in the range [a,b)

The range [a,b) is specified in the constructor.

Other functions are available for generating random quantum states, generating lists of random phases, etc. as follows.

Complex numbers

A complex type that bahaves a bit like std::complex.

Functions

template<std::floating_point Fp = double>
std::ostream &operator<<(std::ostream &stream, qsl::complex<Fp> val)

Print a complex number to an output stream.

namespace qsl

Todo:

At the moment this is only required because of the use of fubiniStudy in the template function below. Maybe the fubiniStudy function should be moved somewhere else.

Todo:

Find a good structure for including these files

Functions

template<std::floating_point Fp>
complex(Fp, Fp) -> complex<Fp>
template<std::floating_point Fp = double>
Fp abs(const complex<Fp> &a)

Compute the absolute value of a complex number.

It is important this has the same name as std::abs so that it can be used in template functions that work for both double and complex types.

Todo:

Maybe it would be good to add an absSquared?

template<std::floating_point Fp = double>
complex<Fp> operator-(const complex<Fp> &a, const complex<Fp> &b)

Compute the difference between two complex numbers.

This function is not meant to be fast

template<std::floating_point Fp = double>
struct complex
#include <complex.hpp>

Struct containing a single complex number.

This class is deliberately minimal to avoid performance problems.

Public Functions

complex(Fp r, Fp i)

Construct a comple number from its real and imaginary parts.

complex()

Make the complex number zero.

Public Members

Fp real
Fp imag

Miscellaneous

Contains miscellaneous useful functions (to be sorted)

Functions

template<typename T>
std::ostream &operator<<(std::ostream &stream, const std::vector<T> &vec)

Print a std::vector of arbitrary type.

namespace qsl

Todo:

At the moment this is only required because of the use of fubiniStudy in the template function below. Maybe the fubiniStudy function should be moved somewhere else.

Todo:

Find a good structure for including these files

Functions

void next(std::size_t &x)

Get the next number with the same number of bits set.

This function will get the next number with the same number of ones as x. The result is stored in x.

This is from here: https://graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation

void printRow(std::string col1, double time1, double time2)

Print the timing results for a benchmark.

void printRow(double time1, double time2)

Print the timing results for a benchmark (no column name)

void printBin(const std::string &name, unsigned int x)

Print a number in binary with a label.

Todo:

The length of the bitstring is hardcoded, fix it

template<typename T>
std::vector<T> operator-(const std::vector<T> &v, const std::vector<T> &w)

Compute the difference between two vector.

This function is not meant to be fast.

template<typename T>
double distance(const std::vector<T> &v1, const std::vector<T> &v2)

Compute the distance between two real or complex vectors.

This function computes the distance between two vectors, which is the norm of their difference. This function is not meant to be fast

template<typename To, typename From>
std::enable_if_t<std::is_convertible_v<From, To>, std::vector<complex<To>>> convertState(const std::vector<complex<From>> &state)

Convert a state vector from one floating point type to another.

This function converts a state vector whose amplitudes use one floating point precision (such as double) to a different floating point precision (such as float). The function is not useful in the normal use of any of the simulators, but is necessary when benchmarking or verifying simulators with different precisions. For example, it might be necessary to instantiate two simulators from the same random state vector with double precision. If one of the simulators uses floats, then the random state vector will need to be converted to float.

Todo:

At the moment, template type checking is performed using SFINAE based on std::enable_if (checking if From is convertible to To). Find a more modern alternative

Parameters

state – The input state vector to be converted

Returns

The state vector in the new floating point precision

template<typename To, typename From>
std::enable_if_t<std::is_convertible_v<From, To>, std::vector<To>> convertVector(const std::vector<From> &v)
unsigned hammingWeight(std::size_t n)

Calculates the hamming weight of an integer.

Counts the number of ones in the binary representation of the integer.

unsigned choose(unsigned n, unsigned k)

Calculates the binomial coefficient n choose k.

std::vector<std::size_t> generateLookup(unsigned len, unsigned ones)

Generate the lookup vector for a given bit-string length and number of ones.

Used in the number preserving simulators