Maestro 0.3.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
AliasBase.h
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cstddef>
5#include <cstdint>
6#include <limits>
7#include <stdexcept>
8#include <vector>
9
10namespace Utils
11{
13{
14 protected:
15 // These are table positions, not state labels. Even a >32-qubit sparse
16 // path-integral state can use compact indices when its support fits.
17 static constexpr bool UseCompactIndices(size_t count)
18 {
19 return count == 0 || count - 1 <= std::numeric_limits<uint32_t>::max();
20 }
21
22 template <class Populate> void SetAliasTable(size_t count, const Populate &populate)
23 {
24 if (count == 0)
25 throw std::domain_error("Alias sampling requires nonempty probability support");
26
27 probabilities.resize(count);
28 if (UseCompactIndices(count))
29 {
30 compactAliases.resize(count);
32 }
33 else
34 {
35 wideAliases.resize(count);
37 }
38 }
39
40 template <class Index, class Populate> void BuildAliasTable(std::vector<Index> &aliases, const Populate &populate)
41 {
42 // Until a row is finalized, its alias slot links to the next row in
43 // its under/over stack. This needs no separate construction buffers.
44 // Counts avoid reserving a sentinel index, so all 2^32 compact rows fit.
45 Index under = 0, over = 0;
46 size_t numUnder = 0, numOver = 0;
47 populate([&](size_t row, double probability) {
48 probabilities[row] = probability;
49 if (probability < 1.)
50 {
51 aliases[row] = under;
52 under = static_cast<Index>(row);
53 ++numUnder;
54 }
55 else
56 {
57 aliases[row] = over;
58 over = static_cast<Index>(row);
59 ++numOver;
60 }
61 });
62
63 while (numUnder && numOver)
64 {
65 const Index u = under, o = over;
66 under = aliases[u];
67 over = aliases[o];
68 --numUnder;
69 --numOver;
70
71 aliases[u] = o;
73 if (probabilities[o] < 1.)
74 {
75 aliases[o] = under;
76 under = o;
77 ++numUnder;
78 }
79 else
80 {
81 aliases[o] = over;
82 over = o;
83 ++numOver;
84 }
85 }
86
87 while (numUnder)
88 {
89 const Index row = under;
90 under = aliases[row];
91 --numUnder;
92 probabilities[row] = 1.;
93 aliases[row] = row;
94 }
95 while (numOver)
96 {
97 const Index row = over;
98 over = aliases[row];
99 --numOver;
100 probabilities[row] = 1.;
101 aliases[row] = row;
102 }
103 }
104
105 size_t SampleIndex(double v) const
106 {
107 const double vadj = v * probabilities.size();
108 const size_t offset = std::min<size_t>(static_cast<size_t>(vadj), probabilities.size() - 1);
109 const double up = std::min<double>(vadj - offset, oneMinusEps);
110 if (up < probabilities[offset])
111 return offset;
112 return compactAliases.empty() ? wideAliases[offset] : compactAliases[offset];
113 }
114
115 std::vector<double> probabilities;
116 std::vector<uint32_t> compactAliases;
117 std::vector<uint64_t> wideAliases;
118 static constexpr double oneMinusEps = 1. - std::numeric_limits<double>::epsilon();
119};
120
121} // namespace Utils
std::vector< double > probabilities
Definition AliasBase.h:115
void SetAliasTable(size_t count, const Populate &populate)
Definition AliasBase.h:22
size_t SampleIndex(double v) const
Definition AliasBase.h:105
static constexpr bool UseCompactIndices(size_t count)
Definition AliasBase.h:17
std::vector< uint32_t > compactAliases
Definition AliasBase.h:116
std::vector< uint64_t > wideAliases
Definition AliasBase.h:117
void BuildAliasTable(std::vector< Index > &aliases, const Populate &populate)
Definition AliasBase.h:40
static constexpr double oneMinusEps
Definition AliasBase.h:118
Portable dense contraction kernels.