Maestro 0.3.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
HermiteInterpolation.h
Go to the documentation of this file.
1
9
10#pragma once
11
12#ifndef __UTILS_HERMITE_INTERPOLATION_H__
13#define __UTILS_HERMITE_INTERPOLATION_H__
14
15#include <boost/math/interpolators/pchip.hpp>
16#include <vector>
17
19
20namespace Utils
21{
22
24{
25 public:
26 template <typename T = size_t> void SetSamples(const std::vector<T> &x, const std::vector<double> &y)
27 {
28 assert(x.size() == y.size());
29 assert(!x.empty());
30 if (x.empty() || y.empty())
31 return;
32
33 spline.reset();
34
35 std::vector<double> xvals(x.begin(), x.end());
36 std::vector<double> yvals = y;
37 x1 = xvals.front();
38 x2 = xvals.back();
39 y1 = yvals.front();
40 y2 = yvals.back();
41
42 if (xvals.size() == 1)
43 slopel = sloper = 0;
44 else
45 {
46 slopel = (yvals[1] - y1) / (xvals[1] - x1);
47 sloper = (y2 - yvals[yvals.size() - 2]) / (x2 - xvals[xvals.size() - 2]);
48 }
49
50 bool fallbackToLinear = false;
51
52 // needs 4 values to work, if we don't have them,
53 // fallback to linear
54 if (xvals.size() < 4)
55 fallbackToLinear = true;
56 else
57 {
58 // check the xvals to ensure they are strictly increasing, otherwise the
59 // pchip interpolator will throw an exception
60 // if that's the case, fallback to linear
61
62 for (size_t i = 1; i < xvals.size(); ++i)
63 if (xvals[i] <= xvals[i - 1])
64 {
65 fallbackToLinear = true;
66 break;
67 }
68 }
69
70 if (fallbackToLinear)
71 {
72 linearExtrapolation = std::make_unique<SimpleLinearRegression<double, double>>();
73 linearExtrapolation->SetTrueLinearRegression(trueInterpolation);
74
75 size_t offset = 0;
76 for (size_t i = 0; i < xvals.size(); ++i)
77 {
78 if (xvals[i] > 1E-12)
79 {
80 offset = i;
81 break;
82 }
83 }
84
85 if (offset > 0)
86 {
87 xvals.erase(xvals.begin(), xvals.begin() + offset);
88 yvals.erase(yvals.begin(), yvals.begin() + offset);
89 }
90
91 linearExtrapolation->SetSamples(xvals, yvals);
92 return;
93 }
94
95 spline = std::make_unique<boost::math::interpolators::pchip<std::vector<double>>>(std::move(xvals), std::move(yvals));
96 }
97
98 double Predict(double x) const
99 {
100 double result = 0;
101
102 const bool smallx = x <= x1;
103 const bool largex = x >= x2;
104 if (smallx || largex)
105 {
106 if (smallx)
107 {
108 if (slopel == 0)
109 result = y1;
110 else
111 result = y1 + slopel * (x - x1);
112 }
113 else
114 {
115 if (sloper == 0)
116 result = y2;
117 else
118 result = y2 + sloper * (x - x2);
119 }
120 }
121 else if (spline)
122 {
123 result = (*spline)(x);
124 }
125 else if (linearExtrapolation)
126 {
127 result = linearExtrapolation->Predict(x);
128 }
129 else
130 {
131 const double slope = (y2 - y1) / (x2 - x1);
132 result = y1 + slope * (x - x1);
133 }
134
135 if (trueInterpolation)
136 return result;
137
138 const auto m = 1E-12;
139 if (result < m)
140 return m;
141
142 return result;
143 }
144
145 void SetTrueInterpolation(bool reg)
146 {
147 trueInterpolation = reg;
148 if (linearExtrapolation)
149 linearExtrapolation->SetTrueLinearRegression(trueInterpolation);
150 }
151
152 private:
153 std::unique_ptr<boost::math::interpolators::pchip<std::vector<double>>> spline;
154 std::unique_ptr<SimpleLinearRegression<double, double>> linearExtrapolation;
155
156 double x1 = 0;
157 double x2 = 0;
158 double y1 = 0;
159 double y2 = 0;
160 double slopel = 0;
161 double sloper = 0;
162
163 // static constexpr double divisor = 8;
164 double minValue = 0;
165 bool trueInterpolation = false;
166};
167
168} // namespace Utils
169
170#endif // __UTILS_HERMITE_INTERPOLATION_H__
double Predict(double x) const
void SetSamples(const std::vector< T > &x, const std::vector< double > &y)
Portable dense contraction kernels.