Maestro 0.3.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
MultivariateHermiteInterpolation.h
Go to the documentation of this file.
1
18
19#pragma once
20
21#ifndef __UTILS_MULTIVARIATE_HERMITE_INTERPOLATION_H__
22#define __UTILS_MULTIVARIATE_HERMITE_INTERPOLATION_H__
23
24#include <cassert>
25#include <memory>
26#include <vector>
27
29
30namespace Utils
31{
32
34{
35 public:
36 // Samples are assumed to be sorted lexicographically by the coordinates in x.
37 // All x[i] must have the same dimension (>= 1).
38 void SetSamples(const std::vector<std::vector<double>> &x, const std::vector<double> &y)
39 {
40 assert(x.size() == y.size());
41 assert(!x.empty());
42
43 if (x.empty() || y.empty())
44 return;
45
46 assert(x[0].size() >= 2);
47
48 leafInterpolator.reset();
49 children.clear();
50 xValues.clear();
51
52 dimension = x[0].size();
53
54 if (dimension == 2)
55 {
56 // degenerate to the bivariate case
57 std::vector<std::vector<double>> xv;
58 xv.reserve(x.size());
59 for (size_t i = 0; i < x.size(); ++i)
60 xv.push_back(x[i]);
61
62 leafInterpolator = std::make_unique<BivariateHermiteInterpolation>();
63 leafInterpolator->SetTrueInterpolation(trueInterpolation);
64 leafInterpolator->SetSamples(xv, y);
65 return;
66 }
67
68 // Group samples by the first coordinate, then recurse on the rest.
69 std::vector<std::vector<double>> subX;
70 std::vector<double> subY;
71
72 auto flushGroup = [&]() {
73 if (subX.empty())
74 return;
75 children.emplace_back(std::make_unique<MultivariateHermiteInterpolation>());
76 children.back()->SetTrueInterpolation(trueInterpolation);
77 children.back()->SetSamples(subX, subY);
78 subX.clear();
79 subY.clear();
80 };
81
82 xValues.push_back(x[0][0]);
83 for (size_t i = 0; i < x.size(); ++i)
84 {
85 assert(x[i].size() == dimension);
86
87 if (x[i][0] != xValues.back())
88 {
89 flushGroup();
90 xValues.push_back(x[i][0]);
91 }
92
93 subX.emplace_back(x[i].begin() + 1, x[i].end());
94 subY.push_back(y[i]);
95 }
96 flushGroup();
97 }
98
99 double Predict(const std::vector<double> &x) const
100 {
101 assert(x.size() == dimension);
102
103 if (dimension < 2 || x.size() != dimension)
104 return 0;
105
106 if (leafInterpolator)
107 return leafInterpolator->Predict(x);
108
109 const std::vector<double> tail(x.begin() + 1, x.end());
110
111 std::vector<double> vals;
112 vals.reserve(children.size());
113 for (size_t i = 0; i < children.size(); ++i)
114 vals.push_back(children[i]->Predict(tail));
115
116 HermiteInterpolation firstInterpolator;
117 firstInterpolator.SetTrueInterpolation(trueInterpolation);
118 firstInterpolator.SetSamples(xValues, vals);
119
120 const double val = firstInterpolator.Predict(x[0]);
121
122 if (trueInterpolation)
123 return val;
124
125 const auto m = 1E-12;
126 if (val < m)
127 return m;
128
129 return val;
130 }
131
132 void SetTrueInterpolation(bool reg)
133 {
134 trueInterpolation = reg;
135
136 if (leafInterpolator)
137 leafInterpolator->SetTrueInterpolation(reg);
138
139 for (auto &child : children)
140 if (child)
141 child->SetTrueInterpolation(reg);
142 }
143
144 private:
145 // Used when dimension == 2.
146 std::unique_ptr<BivariateHermiteInterpolation> leafInterpolator;
147
148 // Used when dimension > 2: one child per unique value of the first coordinate.
149 std::vector<std::unique_ptr<MultivariateHermiteInterpolation>> children;
150 std::vector<double> xValues;
151
152 size_t dimension = 0;
153
154 bool trueInterpolation = false;
155};
156
157} // namespace Utils
158
159#endif // __UTILS_MULTIVARIATE_HERMITE_INTERPOLATION_H__
double Predict(double x) const
void SetSamples(const std::vector< T > &x, const std::vector< double > &y)
void SetSamples(const std::vector< std::vector< double > > &x, const std::vector< double > &y)
double Predict(const std::vector< double > &x) const
Portable dense contraction kernels.