datasketches-cpp
CubicInterpolation-internal.hpp
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #ifndef _CUBICINTERPOLATION_INTERNAL_HPP_
21 #define _CUBICINTERPOLATION_INTERNAL_HPP_
22 
23 #include "CubicInterpolation.hpp"
24 
25 #include <string>
26 #include <stdexcept>
27 
28 namespace datasketches {
29 
30 template<typename A>
31 static double interpolateUsingXAndYTables(const double xArr[], const double yArr[], const int offset, const double x);
32 
33 template<typename A>
34 static double cubicInterpolate(const double x0, const double y0, const double x1, const double y1,
35  const double x2, const double y2, const double x3, const double y3, const double x);
36 
37 template<typename A>
38 static int findStraddle(const double xArr[], const int len, const double x);
39 
40 template<typename A>
41 static int recursiveFindStraddle(const double xArr[], const int l, const int r, const double x);
42 
43 template<typename A>
44 static double interpolateUsingXArrAndYStride(const double xArr[], const double yStride,
45  const int offset, const double x);
46 
47 const int numEntries = 40;
48 
49 //Computed for Coupon lgK = 26 ONLY. Designed for the cubic interpolator function.
50 const double xArrComputed[numEntries] = {
51  0.0, 1.0, 20.0, 400.0,
52  8000.0, 160000.0, 300000.0, 600000.0,
53  900000.0, 1200000.0, 1500000.0, 1800000.0,
54  2100000.0, 2400000.0, 2700000.0, 3000000.0,
55  3300000.0, 3600000.0, 3900000.0, 4200000.0,
56  4500000.0, 4800000.0, 5100000.0, 5400000.0,
57  5700000.0, 6000000.0, 6300000.0, 6600000.0,
58  6900000.0, 7200000.0, 7500000.0, 7800000.0,
59  8100000.0, 8400000.0, 8700000.0, 9000000.0,
60  9300000.0, 9600000.0, 9900000.0, 10200000.0
61 };
62 
63 //Computed for Coupon lgK = 26 ONLY. Designed for the cubic interpolator function.
64 const double yArrComputed[numEntries] = {
65  0.0000000000000000, 1.0000000000000000, 20.0000009437402611, 400.0003963713384110,
66  8000.1589294602090376, 160063.6067763759638183, 300223.7071597663452849, 600895.5933856170158833,
67  902016.8065120954997838, 1203588.4983199508860707, 1505611.8245524743106216, 1808087.9449319066479802,
68  2111018.0231759352609515, 2414403.2270142501220107, 2718244.7282051891088486, 3022543.7025524540804327,
69  3327301.3299219091422856, 3632518.7942584538832307, 3938197.2836029687896371, 4244337.9901093561202288,
70  4550942.1100616492331028, 4858010.8438911894336343, 5165545.3961938973516226, 5473546.9757476449012756,
71  5782016.7955296505242586, 6090956.0727340159937739, 6400366.0287892958149314, 6710247.8893762007355690,
72  7020602.8844453142955899, 7331432.2482349723577499, 7642737.2192891482263803, 7954519.0404754765331745,
73  8266778.9590033423155546, 8579518.2264420464634895, 8892738.0987390466034412, 9206439.8362383283674717,
74  9520624.7036988288164139, 9835293.9703129194676876, 10150448.9097250290215015, 10466090.8000503256917000
75 };
76 
77 template<typename A>
78 double CubicInterpolation<A>::usingXAndYTables(const double x) {
79  return usingXAndYTables(xArrComputed, yArrComputed, numEntries, x);
80 }
81 
82 template<typename A>
83 double CubicInterpolation<A>::usingXAndYTables(const double xArr[], const double yArr[],
84  const int len, const double x) {
85  int offset;
86  if (x < xArr[0] || x > xArr[len-1]) {
87  throw std::invalid_argument("x value out of range: " + std::to_string(x));
88  }
89 
90  if (x == xArr[len-1]) { // corner case
91  return (yArr[len-1]);
92  }
93 
94  offset = findStraddle<A>(xArr, len, x);
95  if (offset < 0 && offset > len-2) {
96  throw std::logic_error("offset must be >= 0 and <= " + std::to_string(len) + "-2");
97  }
98 
99  if (offset == 0) { // corner case
100  return (interpolateUsingXAndYTables<A>(xArr, yArr, (offset-0), x));
101  }
102  else if (offset == numEntries-2) { // corner case
103  return (interpolateUsingXAndYTables<A>(xArr, yArr, (offset-2), x));
104  }
105  // main case
106  return (interpolateUsingXAndYTables<A>(xArr, yArr, (offset-1), x));
107 }
108 
109 // In C: again-two-registers cubic_interpolate_aux L1368
110 template<typename A>
111 static double interpolateUsingXAndYTables(const double xArr[], const double yArr[],
112  const int offset, const double x) {
113  return (cubicInterpolate<A>(xArr[offset+0], yArr[offset+0],
114  xArr[offset+1], yArr[offset+1],
115  xArr[offset+2], yArr[offset+2],
116  xArr[offset+3], yArr[offset+3],
117  x) );
118 }
119 
120 template<typename A>
121 static inline double cubicInterpolate(const double x0, const double y0,
122  const double x1, const double y1,
123  const double x2, const double y2,
124  const double x3, const double y3,
125  const double x)
126 {
127  double l0_numer = (x - x1) * (x - x2) * (x - x3);
128  double l1_numer = (x - x0) * (x - x2) * (x - x3);
129  double l2_numer = (x - x0) * (x - x1) * (x - x3);
130  double l3_numer = (x - x0) * (x - x1) * (x - x2);
131 
132  double l0_denom = (x0 - x1) * (x0 - x2) * (x0 - x3);
133  double l1_denom = (x1 - x0) * (x1 - x2) * (x1 - x3);
134  double l2_denom = (x2 - x0) * (x2 - x1) * (x2 - x3);
135  double l3_denom = (x3 - x0) * (x3 - x1) * (x3 - x2);
136 
137  double term0 = y0 * l0_numer / l0_denom;
138  double term1 = y1 * l1_numer / l1_denom;
139  double term2 = y2 * l2_numer / l2_denom;
140  double term3 = y3 * l3_numer / l3_denom;
141 
142  return (term0 + term1 + term2 + term3);
143 }
144 
145 /* returns j such that xArr[j] <= x and x < xArr[j+1] */
146 template<typename A>
147 static int findStraddle(const double xArr[], const int len, const double x)
148 {
149  if ((len < 2) || (x < xArr[0]) || (x > xArr[len-1])) {
150  throw std::logic_error("invariant violated during interpolation");
151  }
152  return(recursiveFindStraddle<A>(xArr, 0, len-1, x));
153 }
154 
155 
156 /* the invariant here is that xArr[l] <= x && x < xArr[r] */
157 template<typename A>
158 static int recursiveFindStraddle(const double xArr[], const int l, const int r, const double x)
159 {
160  int m;
161  if (l >= r) {
162  throw std::logic_error("lower bound not less than upper bound in search");
163  }
164  if ((xArr[l] > x) || (x >= xArr[r])) { // the invariant
165  throw std::logic_error("target value invariant violated in search");
166  }
167 
168  if (l+1 == r) return (l);
169  m = l + ((r-l)/2);
170  if (xArr[m] <= x) return (recursiveFindStraddle<A>(xArr, m, r, x));
171  else return (recursiveFindStraddle<A>(xArr, l, m, x));
172 }
173 
174 
175 //Interpolate using X table and Y stride
176 
186 //In C: again-two-registers cubic_interpolate_with_x_arr_and_y_stride L1411
187 // Used by HllEstimators
188 template<typename A>
189 double CubicInterpolation<A>::usingXArrAndYStride(const double xArr[], const int xArrLen,
190  const double yStride, const double x) {
191  const int xArrLenM1 = xArrLen - 1;
192 
193  if ((xArrLen < 4) || (x < xArr[0]) || (x > xArr[xArrLenM1])) {
194  throw std::logic_error("impossible values during interpolaiton");
195  }
196 
197  if (x == xArr[xArrLenM1]) { /* corner case */
198  return (yStride * (xArrLenM1));
199  }
200 
201  const int offset = findStraddle<A>(xArr, xArrLen, x); //uses recursion
202  const int xArrLenM2 = xArrLen - 2;
203  if ((offset < 0) || (offset > xArrLenM2)) {
204  throw std::logic_error("invalid offset during interpolation");
205  }
206 
207  if (offset == 0) { /* corner case */
208  return (interpolateUsingXArrAndYStride<A>(xArr, yStride, (offset - 0), x));
209  }
210  else if (offset == xArrLenM2) { /* corner case */
211  return (interpolateUsingXArrAndYStride<A>(xArr, yStride, (offset - 2), x));
212  }
213  /* main case */
214  return (interpolateUsingXArrAndYStride<A>(xArr, yStride, (offset - 1), x));
215 }
216 
217 //In C: again-two-registers cubic_interpolate_with_x_arr_and_y_stride_aux L1402
218 template<typename A>
219 static double interpolateUsingXArrAndYStride(const double xArr[], const double yStride,
220  const int offset, const double x) {
221  return cubicInterpolate<A>(
222  xArr[offset + 0], yStride * (offset + 0),
223  xArr[offset + 1], yStride * (offset + 1),
224  xArr[offset + 2], yStride * (offset + 2),
225  xArr[offset + 3], yStride * (offset + 3),
226  x);
227 }
228 
229 }
230 
231 #endif // _CUBICINTERPOLATION_INTERNAL_HPP_
DataSketches namespace.
Definition: binomial_bounds.hpp:38