C++ API

The C++ API reference is generated from the public headers and pybind11 binding source.

Decision Diagram Header

Typedefs

using std_complex = Complex
using Controls = std::set<Control, ControlComparator>

Functions

inline Complex operator+(Complex lhs, const Complex &rhs) noexcept
inline Complex operator-(Complex lhs, const Complex &rhs) noexcept
inline Complex operator*(Complex lhs, const Complex &rhs) noexcept
inline Complex operator/(Complex lhs, const Complex &rhs) noexcept
inline std::ostream &operator<<(std::ostream &os, const Complex &c) noexcept
inline double norm(const Complex &c)
inline double norm2(const Complex &c)
inline double canonicalize_component(double x) noexcept
inline double canonicalize_special_component(double x) noexcept
inline std_complex canonicalize_complex(std_complex z) noexcept
inline std_complex canonicalize_special_complex(std_complex z) noexcept
inline void swap(vEdge &lhs, vEdge &rhs)
inline void swap(mEdge &lhs, mEdge &rhs)
inline std::ostream &operator<<(std::ostream &os, const mEdge &c)
inline bool operator<(const Control &lhs, const Control &rhs)
inline bool operator==(const Control &lhs, const Control &rhs)
inline bool operator!=(const Control &lhs, const Control &rhs)
mEdge makeMEdge(Qubit q, const std::array<mEdge, 4> &c)
mEdge makeIdent(Qubit q)
mEdge makeGate(QubitCount q, GateMatrix g, Qubit target, const Controls &c)
mEdge makeGate(QubitCount q, GateMatrix g, Qubit target)
mEdge makeTwoQubitGate(QubitCount q, TwoQubitGateMatrix g, Qubit target0, Qubit target1, const Controls &c)
mEdge makeTwoQubitGate(QubitCount q, TwoQubitGateMatrix g, Qubit target0, Qubit target1)
mEdge makeLargeGate(QubitCount q, ComplexMatrix &g)
mEdge makeLargeGate(QubitCount q, ComplexMatrix &g, const std::vector<Qubit> &targets)
mEdge makeLargeGate(ComplexMatrix &g, const Qubit level, const std::size_t rowStart, const std::size_t rowEnd, const std::size_t colStart, const std::size_t colEnd, const std::vector<bool> skip, const Qubit target_min)
mEdge getMPIGate(mEdge root, int row, int col, int world_size, Qubit current_var)
mEdge mm_add(const mEdge &lhs, const mEdge &rhs)
mEdge mm_multiply(const mEdge &lhs, const mEdge &rhs)
mEdge mm_kronecker(const mEdge &lhs, const mEdge &rhs)
vEdge vv_add(const vEdge &lhs, const vEdge &rhs)
vEdge vv_kronecker(const vEdge &lhs, const vEdge &rhs)
vEdge mv_multiply(mEdge lhs, vEdge rhs)
vEdge makeVEdge(Qubit q, const std::array<vEdge, 2> &c)
vEdge makeZeroState(QubitCount q)
vEdge makeOneState(QubitCount q)
std::string measureAll(vEdge &rootEdge, const bool collapse, std::mt19937_64 &mt, double epsilon = 0.001)
char measureOneCollapsing(vEdge &rootEdge, const Qubit index, std::mt19937_64 &mt, double epsilon = 0.001)
double measureOne(vEdge &rootEdge, const Qubit index, std::mt19937_64 &mt, double epsilon = 0.001)
std::vector<double> probabilities(const vEdge &rootEdge)
mEdge RX(QubitCount qnum, int target, double angle)
mEdge RY(QubitCount qnum, int target, double angle)
mEdge RZ(QubitCount qnum, int target, double angle)
mEdge CX(QubitCount qnum, int target, int control)
GateMatrix rx(double angle)
GateMatrix ry(double angle)
GateMatrix rz(double angle)
GateMatrix u3(double theta, double phi, double lambda)
GateMatrix u1(double lambda)
GateMatrix u2(double phi, double lambda)
GateMatrix u(double theta, double phi, double lambda, double gamma)
GateMatrix p(double angle)
GateMatrix r(double theta, double phi)
mEdge makeSwap(QubitCount qnum, int target0, int target1)
mEdge RXX(QubitCount qnum, int target0, int target1, double angle)
mEdge RYY(QubitCount qnum, int target0, int target1, double angle)
mEdge RZZ(QubitCount qnum, int target0, int target1, double angle)
mEdge RZX(QubitCount qnum, int target0, int target1, double angle)
mEdge SWAP(QubitCount qnum, int target0, int target1)
mEdge ISWAP(QubitCount qnum, int target0, int target1)
mEdge CSWAP(QubitCount qnum, int target0, int target1, int control)
TwoQubitGateMatrix rxx_matrix(double angle)
TwoQubitGateMatrix ryy_matrix(double angle)
TwoQubitGateMatrix rzz_matrix(double angle)
TwoQubitGateMatrix rzx_matrix(double angle)
TwoQubitGateMatrix swap_matrix()
TwoQubitGateMatrix iswap_matrix()
std::string genDot(vEdge &rootEdge)
std::string genDot(mEdge &rootEdge)
int get_nNodes(vEdge e)
vEdge gc(vEdge state, bool force = false)
std::vector<vEdge> gc(std::vector<vEdge> state, bool force = false)
mEdge gc_mat(mEdge mat, bool force = false)
std::vector<mEdge> gc_mat(std::vector<mEdge> mat, bool force = false)
void clear_cache(bool force = false)
void set_gc_thr(int gc_v, int gc_m)

Variables

std::vector<mEdge> identityTable
struct Complex
#include <dd.h>

Lightweight complex number used as a decision diagram edge weight.

QDD uses this type instead of std::complex so that equality, approximate comparisons, hashing, and optional MPI serialization remain consistent across vector and matrix decision diagram operations.

Public Functions

Complex() = default
inline Complex(const std::complex<double> &c)
inline Complex(double rr, double ii)
inline Complex &operator+=(const Complex &rhs) noexcept
inline Complex &operator-=(const Complex &rhs) noexcept
inline Complex &operator*=(const Complex &rhs) noexcept
inline Complex &operator/=(const Complex &rhs) noexcept
inline double mag2() const
inline bool isZero() const noexcept
inline bool isApproximatelyZero() const noexcept
inline bool isApproximatelyEqual(const Complex &rhs) const noexcept
inline bool isApproximatelyOne() const noexcept
inline bool isOne() const noexcept
inline bool operator==(const Complex &rhs) const noexcept
inline bool operator==(const std::complex<double> rhs) const noexcept
inline double real() const noexcept
inline double imag() const noexcept

Public Members

double r = {0.0}
double i = {0.0}

Public Static Attributes

static const double TOLERANCE = std::numeric_limits<double>::epsilon() * 1024
struct vEdge
#include <dd.h>

Weighted edge in a vector decision diagram.

A vector edge combines a complex weight with a pointer to a vector node. The terminal and zero edges are represented by the static members of this type.

Public Functions

inline Qubit getVar() const noexcept
inline bool isTerminal() const noexcept
inline vNode *getNode() const
void printVector() const
void printVector_sparse() const
std_complex *getVector(std::size_t *dim) const
VectorXcf getEigenVector()
inline bool operator==(const vEdge &e) const noexcept

Public Members

std_complex w
vNode *n = {nullptr}

Public Static Attributes

static vEdge one
static vEdge zero
struct vNode
#include <dd.h>

Node in a vector decision diagram.

Each vector node is associated with a qubit variable and has two child edges, corresponding to the low and high branches of that variable.

Public Functions

vNode() = default
inline vNode(const vNode &vv)
inline vNode(Qubit q, const std::array<vEdge, 2> &c, vNode *n)
inline vNode(Qubit q, const std::array<vEdge, 2> &c, vNode *n, vNode*)
inline vEdge &operator[](std::size_t i)
inline vEdge &getEdge(std::size_t i)
inline bool operator==(const vNode &n) const noexcept

Public Members

Qubit v
std::array<vEdge, 2> children
vNode *next = {nullptr}

Public Static Attributes

static vNode terminalNode
static constexpr vNode *terminal = {&terminalNode}
struct mEdge
#include <dd.h>

Weighted edge in a matrix decision diagram.

A matrix edge combines a complex weight with a pointer to a matrix node. The edge is the public handle used by matrix operations and Python bindings.

Public Functions

inline Qubit getVar() const noexcept
inline bool isTerminal() const noexcept
inline mNode *getNode() const
void printMatrix(Qubit nQubits = -1) const
std_complex **getMatrix(std::size_t *dim, Qubit nQubits = -1) const
MatrixXcf getEigenMatrix(Qubit nQubits)
inline bool operator==(const mEdge &e) const noexcept
inline bool operator!=(const mEdge &e) const noexcept

Public Members

std_complex w
mNode *n = {nullptr}

Public Static Attributes

static mEdge one
static mEdge zero
template<>
struct hash<std_complex>
#include <dd.h>

Public Functions

inline std::size_t operator()(const std_complex &v) const noexcept
template<>
struct hash<mEdge>
#include <dd.h>

Public Functions

inline std::size_t operator()(const mEdge &e) const noexcept
template<>
struct hash<vEdge>
#include <dd.h>

Public Functions

inline std::size_t operator()(const vEdge &e) const noexcept
struct mNode
#include <dd.h>

Node in a matrix decision diagram.

Each matrix node is associated with a qubit variable and has four child edges, corresponding to the 2x2 block decomposition of an operator.

Public Functions

mNode() = default
inline mNode(Qubit q, const std::array<mEdge, 4> &c, mNode *n)
inline mNode(Qubit q, const std::array<mEdge, 4> &c, mNode *n, mNode*)
inline mNode(const mNode &vv)
inline mEdge &operator[](std::size_t i)
inline mEdge &getEdge(std::size_t i)
inline bool operator==(const mNode &n) const noexcept

Public Members

Qubit v
std::array<mEdge, 4> children
mNode *next = {nullptr}

Public Static Attributes

static mNode terminalNode
static constexpr mNode *terminal = {&terminalNode}
template<>
struct hash<mNode>
#include <dd.h>

Public Functions

inline std::size_t operator()(const mNode &n) const noexcept
template<>
struct hash<vNode>
#include <dd.h>

Public Functions

inline std::size_t operator()(const vNode &n) const noexcept
struct MEdgeExactEqual
#include <dd.h>

Public Functions

inline bool operator()(const mEdge &lhs, const mEdge &rhs) const noexcept
struct VEdgeExactEqual
#include <dd.h>

Public Functions

inline bool operator()(const vEdge &lhs, const vEdge &rhs) const noexcept
struct MNodeExactEqual
#include <dd.h>

Public Functions

inline bool operator()(const mNode &lhs, const mNode &rhs) const noexcept
struct VNodeExactEqual
#include <dd.h>

Public Functions

inline bool operator()(const vNode &lhs, const vNode &rhs) const noexcept
struct Control
#include <dd.h>

Control qubit descriptor for controlled gate construction.

Public Types

enum class Type : bool

Values:

enumerator pos
enumerator neg

Public Members

Qubit qubit
Type type = Type::pos
struct ControlComparator
#include <dd.h>

Public Functions

inline bool operator()(const Control &lhs, const Control &rhs) const
inline bool operator()(Qubit lhs, const Control &rhs) const
inline bool operator()(const Control &lhs, Qubit rhs) const
struct vContent
#include <dd.h>

Public Functions

inline vContent(Qubit qpos, std_complex w1, std_complex w2, int i1, int i2)
inline vContent()

Public Members

Qubit v
std::array<std_complex, 2> w
std::array<int, 2> index
struct mContent
#include <dd.h>

Public Functions

inline mContent(Qubit qpos, std_complex w1, std_complex w2, std_complex w3, std_complex w4, int i1, int i2, int i3, int i4)
inline mContent()

Public Members

Qubit v
std::array<std_complex, 4> w
std::array<int, 4> index

Cache Header

Variables

constexpr std::size_t hardware_constructive_interference_size = 64
constexpr std::size_t hardware_destructive_interference_size = 64
AddCache _aCache
MulCache _mCache
class AddCache
#include <cache.hpp>

Memoization cache for decision diagram addition.

The cache stores results of vector-vector and matrix-matrix addition keyed by operand edges. It reduces repeated recursive work during decision diagram arithmetic.

Public Functions

inline AddCache(QubitCount q)
template<typename T>
inline T find(T lhs, T rhs)
template<typename T>
inline void set(T lhs, T rhs, const T &result)
inline void clearAll()
inline double hitRatio() const noexcept
inline std::size_t getSize()

Private Functions

inline Bucket *getBucket()
template<typename T>
inline std::size_t hash(const T &lhs, const T &rhs)
template<typename T>
inline T find_in_bucket(Table &t, std::size_t key, const T &l, const T &r)
template<typename T>
inline void set(Entry &e, const T &l, const T &r, const T &res)
template<typename T>
inline void set_in_bucket(Table &t, std::size_t key, const T &l, const T &r, const T &result)

Private Members

Cache c
std::vector<std::vector<Table>> _tables
std::mt19937_64 rng
std::uniform_int_distribution<int> dist
std::size_t lookups = {0}
std::size_t hits = {0}
struct Bucket

Public Members

Entry e
struct Cache

Public Functions

inline Cache()

Public Members

std::vector<std::vector<Bucket>> chunks
std::size_t chunkID = {0}
std::vector<Bucket>::iterator chunkIt
std::vector<Bucket>::iterator chunkEndIt
std::size_t allocationSize = {INITIAL_ALLOCATION_SIZE_CACHE * GROWTH_FACTOR}
std::size_t allocations = INITIAL_ALLOCATION_SIZE_CACHE
union Edge

Public Functions

inline Edge()

Public Members

mEdge m
vEdge v
struct Entry

Public Functions

inline Entry()

Public Members

Edge lhs
Edge rhs
Edge result
bool valid
struct Table

Public Members

Bucket *_table[NBUCKETS] = {nullptr}
class MulCache
#include <cache.hpp>

Memoization cache for decision diagram multiplication.

The cache stores multiplication results for edge operands and is shared by matrix-vector and matrix-matrix recursive operations.

Public Functions

inline MulCache(QubitCount q)
template<typename LT, typename RT, typename RetT = std::conditional_t<std::is_same_v<RT, vNode>, vEdge, mEdge>>
inline RetT find(const LT *lhs, const RT *rhs)
template<typename LT, typename RT, typename ResT = std::conditional_t<std::is_same_v<RT, vNode>, vEdge, mEdge>>
inline void set(const LT *lhs, const RT *rhs, const ResT &result)
inline void clearAll()
inline double hitRatio() const noexcept
inline std::size_t getSize()

Private Functions

inline Bucket *getBucket()
template<typename RET>
inline RET find_in_bucket(Table &t, std::size_t key, uintptr_t l, uintptr_t r)
template<typename T>
inline void set(Entry &e, uintptr_t &l, uintptr_t &r, const T &res)
template<typename ResT>
inline void set_in_bucket(Table &t, std::size_t key, uintptr_t l, uintptr_t r, const ResT &result)

Private Members

Cache c
std::vector<std::vector<Table>> _tables
std::mt19937_64 rng
std::uniform_int_distribution<int> dist
std::size_t lookups = {0}
std::size_t hits = {0}

Private Static Functions

static inline std::size_t bucket_key(uintptr_t l, uintptr_t r) noexcept
struct Bucket

Public Members

Entry es[4]
struct Cache

Public Functions

inline Cache()

Public Members

std::vector<std::vector<Bucket>> chunks
std::size_t chunkID = {0}
std::vector<Bucket>::iterator chunkIt
std::vector<Bucket>::iterator chunkEndIt
std::size_t allocationSize = {INITIAL_ALLOCATION_SIZE_CACHE * GROWTH_FACTOR}
std::size_t allocations = INITIAL_ALLOCATION_SIZE_CACHE
union Edge

Public Functions

inline Edge()

Public Members

mEdge m
vEdge v
struct Entry

Public Functions

inline Entry()

Public Members

uintptr_t lhs
uintptr_t rhs
Edge result
bool valid
int picked
struct Table

Public Members

Bucket *_table[NBUCKETS] = {nullptr}

Table Header

Typedefs

using mNodeTable = CHashTable<mNode, std::hash<mNode>, MNodeExactEqual>
using vNodeTable = CHashTable<vNode, std::hash<vNode>, VNodeExactEqual>

Variables

static const uint64_t CL_MASK = ~(((LINE_SIZE) / 8) - 1)
static const uint64_t CL_MASK_R = ((LINE_SIZE) / 8) - 1
mNodeTable mUnique
vNodeTable vUnique
template<typename T, typename Hash = std::hash<T>, typename ValueEqual = std::equal_to<T>>
class CHashTable
#include <table.hpp>

Unique table and node allocator for decision diagram nodes.

The table interns equivalent nodes per qubit variable and reuses returned nodes through an internal free list. This keeps canonical decision diagram nodes shared across operations.

Public Functions

inline CHashTable(QubitCount n)
inline QubitCount getQubitCount() const
inline T *getNode()
inline void returnNode(T *p)
inline T *register_wo_lookup(T *node)
inline T *lookup(T *node)
inline void dump()
inline std::size_t get_allocations()

Private Members

std::vector<Table> _tables
std::size_t collected
Cache _cache
QubitCount _qn

Private Static Functions

static inline constexpr bool is_power_of_two(std::size_t x) noexcept
static inline constexpr std::size_t bucket_index(std::size_t h) noexcept
struct Cache

Public Types

using Allocator = std::allocator<T>
using AllocatorTraits = std::allocator_traits<Allocator>

Public Functions

inline Cache()
inline ~Cache()
Cache(const Cache&) = delete
Cache &operator=(const Cache&) = delete
inline Cache(Cache &&other) noexcept
inline Cache &operator=(Cache &&other) noexcept
inline void addChunk(std::size_t capacity)

Public Members

T *available = {}
std::vector<Chunk> chunks = {}
std::size_t chunkID = {0}
T *chunkIt = {nullptr}
T *chunkEndIt = {nullptr}
std::size_t allocationSize = {INITIAL_ALLOCATION_SIZE * GROWTH_FACTOR}
std::size_t allocations = {0}
Allocator allocator = {}

Private Functions

inline void clear() noexcept
inline void moveFrom(Cache &&other) noexcept
struct Chunk
#include <table.hpp>

Public Members

T *data = {nullptr}
std::size_t capacity = {0}
std::size_t constructed = {0}
struct NodeSlot

Public Members

T *node
struct Table

Public Members

NodeSlot _table[NBUCKETS] = {nullptr}

Common Types

Defines

LINE_SIZE
WORKERS
cas(ptr, old, new)

Typedefs

using duration_micro = std::chrono::duration<double, std::micro>
using Qubit = int32_t
using QubitCount = uint32_t
using Index = std::size_t
using double_pair = std::pair<double, double>
using GateMatrix = std::array<std::complex<double>, 4>
using TwoQubitGateMatrix = std::array<std::array<std::complex<double>, 4>, 4>
using ComplexMatrix = std::vector<std::vector<std::complex<double>>>

Functions

inline Index operator""_idx(unsigned long long int idx)
inline Qubit operator""_q(unsigned long long int q)
constexpr std::size_t hash_combine(std::size_t lhs, std::size_t rhs)
constexpr std::size_t murmur_hash(std::size_t k)

Variables

const std::size_t NQUBITS = 100
const std::size_t NBUCKETS = 524288
const std::size_t INITIAL_ALLOCATION_SIZE = 1024 * 2
const std::size_t INITIAL_ALLOCATION_SIZE_CACHE = 1024 * 8
const std::size_t GROWTH_FACTOR = 2
const Index TERMINAL = 0_idx
const uint64_t INDEX_MASK = 0x00000000FFFFFFFFLL
const uint64_t HASH_MASK = 0xFFFFFFFF00000000LL
const uint64_t HASH_SHIFT = 32
const std::size_t REGION_SIZE = 512
const uint64_t UT_INIT_SZ = 8 * REGION_SIZE
const uint64_t UT_MAX_SZ = 16 * REGION_SIZE
constexpr double SQRT2 = 0.707106781186547524400844362104849039284835937688474036588L
constexpr double PI = 3.141592653589793238462643383279502884L
constexpr std::complex<double> cf_one = {1., 0.}
constexpr std::complex<double> cf_mone = {-1., 0.}
constexpr std::complex<double> cf_zero = {0., 0.}
constexpr std::complex<double> cf_i = {0., 1.}
constexpr std::complex<double> cf_mi = {0., -1.}
constexpr std::complex<double> cf_SQRT2_2 = {SQRT2, 0.}
constexpr std::complex<double> cf_mSQRT2_2 = {-SQRT2, 0.}
constexpr std::complex<double> cf_iSQRT2_2 = {0., SQRT2}
constexpr std::complex<double> cf_miSQRT2_2 = {0., -SQRT2}
constexpr std::complex<double> cf_1plusi = {SQRT2, SQRT2}
constexpr std::complex<double> cf_1minusi = {SQRT2, -SQRT2}
constexpr std::complex<double> cf_1plusi_2 = {0.5, 0.5}
constexpr std::complex<double> cf_1minusi_2 = {0.5, -0.5}
constexpr GateMatrix Imat = {cf_one, cf_zero, cf_zero, cf_one}
constexpr GateMatrix Hmat = {cf_SQRT2_2, cf_SQRT2_2, cf_SQRT2_2, cf_mSQRT2_2}
constexpr GateMatrix Xmat = {cf_zero, cf_one, cf_one, cf_zero}
constexpr GateMatrix Ymat = {cf_zero, cf_mi, cf_i, cf_zero}
constexpr GateMatrix Zmat = {cf_one, cf_zero, cf_zero, cf_mone}
constexpr GateMatrix Smat = {cf_one, cf_zero, cf_zero, cf_i}
constexpr GateMatrix Sdagmat = {cf_one, cf_zero, cf_zero, cf_mi}
constexpr GateMatrix Tmat = {cf_one, cf_zero, cf_zero, cf_1plusi}
constexpr GateMatrix Tdagmat = {cf_one, cf_zero, cf_zero, cf_1minusi}
constexpr GateMatrix SXmat = {cf_1plusi_2, cf_1minusi_2, cf_1minusi_2, cf_1plusi_2}
constexpr GateMatrix SXdagmat = {cf_1minusi_2, cf_1plusi_2, cf_1plusi_2, cf_1minusi_2}
constexpr GateMatrix Vmat = {cf_SQRT2_2, cf_miSQRT2_2, cf_miSQRT2_2, cf_SQRT2_2}
constexpr GateMatrix Vdagmat = {cf_SQRT2_2, cf_iSQRT2_2, cf_iSQRT2_2, cf_SQRT2_2}
template<typename T, typename ...Ts>
constexpr auto get_index_v = get_index<T, Ts...>::value
struct c
#include <common.h>

Public Functions

inline c(const std::complex<double> &cf)

Public Members

double r
double i
template<size_t I, typename ...Ts>
struct get_index_impl
#include <common.h>
template<size_t I, typename T, typename ...Ts>
struct get_index_impl<I, T, T, Ts...> : public std::integral_constant<size_t, I>
#include <common.h>
template<size_t I, typename T, typename U, typename ...Ts>
struct get_index_impl<I, T, U, Ts...> : public get_index_impl<I + 1, T, Ts...>
#include <common.h>
template<typename T, typename ...Ts>
struct get_index<T, std::variant<Ts...>> : public get_index_impl<0, T, Ts...>
#include <common.h>