Maestro 0.3.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
Alias.h
Go to the documentation of this file.
1
9
10#pragma once
11
12#ifndef _ALIAS_H_
13#define _ALIAS_H_
14
15#include "AliasBase.h"
16#include <algorithm>
17#include <cmath>
18#include <complex>
19#include <cstdint>
20#include <limits>
21#include <stdexcept>
22#include <vector>
23
24#include <Eigen/Eigen>
25
26#include "PathIntegral.h"
27#include <type_traits>
28#include <utility>
29
30namespace Utils
31{
32
33using PathIntegralAmplitudeMap = std::remove_reference_t<decltype(std::declval<QC::PathIntegral::PathIntegralSimulator &>().GetAmplitudes())>;
34
35// Path-integral pruning can leave a non-unit norm. Sample conditionally
36// on the finite, positive retained mass, just as direct measurement does.
37inline double PathIntegralMass(const PathIntegralAmplitudeMap &amplitudes)
38{
39 double total = 0.;
40 for (const auto &entry : amplitudes)
41 total += std::norm(entry.second);
42 if (!(total > 0.) || !std::isfinite(total))
43 throw std::domain_error("Path integral sampling requires finite positive probability mass");
44 return total;
45}
46
47class Alias : public AliasBase
48{
49 public:
50 Alias() = delete;
51
52 template <class T = Eigen::VectorXcd> Alias(const T &statevector)
53 {
54 size_t numNonZeroStates = 0;
55 bool contiguousStates = true;
56 double accum = 0.;
57 for (Eigen::Index state = 0; state < static_cast<Eigen::Index>(statevector.size()); ++state)
58 {
59 const double stateProb = std::norm(statevector[state]);
60 if (stateProb < std::numeric_limits<double>::epsilon())
61 continue;
62
63 contiguousStates = contiguousStates && static_cast<size_t>(state) == numNonZeroStates;
64 ++numNonZeroStates;
65
66 accum += stateProb;
67 if (accum > oneMinusEps)
68 break;
69 }
70
71 // Dense states (and contiguous prefixes) map table positions directly
72 // to outcomes. Keep the full-width mapping only for sparse support.
73 if (!contiguousStates)
74 statesTable.reserve(numNonZeroStates);
75
76 SetAliasTable(numNonZeroStates, [&](const auto &add) {
77 size_t row = 0;
78 double sum = 0.;
79 for (Eigen::Index state = 0; state < static_cast<Eigen::Index>(statevector.size()); ++state)
80 {
81 const double stateProb = std::norm(statevector[state]);
82 if (stateProb < std::numeric_limits<double>::epsilon())
83 continue;
84
85 add(row++, stateProb * numNonZeroStates);
86 if (!contiguousStates)
87 statesTable.push_back(state);
88
89 sum += stateProb;
90 if (sum > oneMinusEps)
91 break;
92 }
93 });
94 }
95
96 Alias(const PathIntegralAmplitudeMap &amplitudesMap)
97 {
98 const double total = PathIntegralMass(amplitudesMap);
99 statesTable.reserve(amplitudesMap.size());
100 SetAliasTable(amplitudesMap.size(), [&](const auto &add) {
101 size_t row = 0;
102 for (const auto &entry : amplitudesMap)
103 {
104 add(row++, (std::norm(entry.second) / total) * amplitudesMap.size());
105 statesTable.push_back(entry.first.getWords()[0]);
106 }
107 });
108 }
109
110 inline size_t Sample(double v) const
111 {
112 const size_t row = SampleIndex(v);
113 return statesTable.empty() ? row : statesTable[row];
114 }
115
116 private:
117 std::vector<uint64_t> statesTable;
118};
119
120class AliasBig : public AliasBase
121{
122 public:
123 AliasBig() = delete;
124
125 AliasBig(const PathIntegralAmplitudeMap &amplitudesMap)
126 {
127 const double total = PathIntegralMass(amplitudesMap);
128 qubitCount = amplitudesMap.QubitCount();
129 wordsPerState = (qubitCount + 63) / 64;
130 if (wordsPerState && amplitudesMap.size() > statesTable.max_size() / wordsPerState)
131 throw std::length_error("Alias state labels exceed maximum storage size");
132 // All keys share a width. Store just their active words instead of a
133 // fixed 1024-bit FastVectorBool per entry, without truncating high bits.
134 statesTable.reserve(amplitudesMap.size() * wordsPerState);
135 SetAliasTable(amplitudesMap.size(), [&](const auto &add) {
136 size_t row = 0;
137 for (const auto &entry : amplitudesMap)
138 {
139 add(row, (std::norm(entry.second) / total) * amplitudesMap.size());
140 if (wordsPerState)
141 statesTable.insert(statesTable.end(), entry.first.getWords(), entry.first.getWords() + wordsPerState);
142 ++row;
143 }
144 });
145 }
146
147 inline QC::PathIntegral::FastVectorBool Sample(double v) const
148 {
149 const size_t row = SampleIndex(v);
150 if (!wordsPerState)
151 return QC::PathIntegral::FastVectorBool();
152 return QC::PathIntegral::FastVectorBool(statesTable.data() + row * wordsPerState, qubitCount);
153 }
154
155 private:
156 std::vector<uint64_t> statesTable;
157 size_t qubitCount = 0;
158 size_t wordsPerState = 0;
159};
160
161} // namespace Utils
162
163#endif // _ALIAS_H_
void SetAliasTable(size_t count, const Populate &populate)
Definition AliasBase.h:22
size_t SampleIndex(double v) const
Definition AliasBase.h:105
static constexpr double oneMinusEps
Definition AliasBase.h:118
AliasBig()=delete
QC::PathIntegral::FastVectorBool Sample(double v) const
Definition Alias.h:147
AliasBig(const PathIntegralAmplitudeMap &amplitudesMap)
Definition Alias.h:125
Alias(const T &statevector)
Definition Alias.h:52
Alias(const PathIntegralAmplitudeMap &amplitudesMap)
Definition Alias.h:96
Alias()=delete
size_t Sample(double v) const
Definition Alias.h:110
Portable dense contraction kernels.
std::remove_reference_t< decltype(std::declval< QC::PathIntegral::PathIntegralSimulator & >().GetAmplitudes())> PathIntegralAmplitudeMap
Definition Alias.h:33
double PathIntegralMass(const PathIntegralAmplitudeMap &amplitudes)
Definition Alias.h:37