Turi Create  4.0
interpolate_value.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5  */
6 #ifndef RESAMPLE_INTERPOLATE_VALUE_H
7 #define RESAMPLE_INTERPOLATE_VALUE_H
8 
9 #include <core/data/flexible_type/flexible_type.hpp>
10 
11 namespace turi {
12 namespace timeseries {
13 
14 /**
15  * Simple interface for 2-D interpolation required for re-sample.
16  * functions.
17  *
18  * \code
19  * output = interpolator.emit(1.5, 1, 1, 2, 2)
20  * \endcode
21  *
22  * As an example, consider the following simple function which interpolates
23  * values linearly.
24  *
25  * Interpolates the value at t, using the values at (t1, v1), (t2, v2)
26  * \code
27  linear = [](const flexible_type& t,
28  const flexible_type& t1, const flexible_type& t2,
29  const flexible_type& v1, const flexible_type& v2) {
30  return v1 + (v2 - v2) * (t - t1) / (t2 - t1);
31  }
32  *
33  * \endcode
34  */
35 
37 
38  public:
39  /**
40  * Returns true if the the aggregate_value can consume a column of this type,
41  * and false otherwise. (For instance, a sum aggregator can consume integers
42  * and floats, and not anything else).
43  */
44  virtual bool support_type(flex_type_enum type) const = 0;
45 
46  /**
47  * Sets the input types and returns the output type.
48  *
49  * Default implementation assumes there is ony one input, and output
50  * type is the same as input type.
51  */
52  virtual flex_type_enum set_input_types(const std::vector<flex_type_enum>&
53  types) {
54  DASSERT_TRUE(types.size() == 1);
55  return set_input_type(types[0]);
56  }
57 
58  /**
59  * Returns a printable name of the operation.
60  */
61  virtual std::string name() const = 0;
62 
63  /**
64  * Interpolate the value at t, given the (t1, v1) and (t2, v2)
65  */
66  virtual flexible_type interpolate(
67  const flexible_type& t, const flexible_type& t1, const flexible_type& t2,
68  const flexible_type& v1, const flexible_type& v2) const = 0;
69 
70  protected:
71  virtual flex_type_enum set_input_type(flex_type_enum type) {
72  return type;
73  }
74 };
75 
76 class zero_fill : public interpolator_value {
77  public:
78 
79  bool support_type(flex_type_enum type) const {
80  return (type == flex_type_enum::INTEGER) ||
81  (type == flex_type_enum::FLOAT) ||
82  (type == flex_type_enum::VECTOR);
83  }
84 
85  std::string name() const {
86  return std::string("zero");
87  }
88 
90  const flexible_type& t2, const flexible_type& v1,
91  const flexible_type& v2) const {
92  if (v1.get_type() == flex_type_enum::VECTOR ||
94  // First or last may be None.
95  if (v1.get_type() == flex_type_enum::VECTOR) {
96  return flexible_type(flex_vec(v1.size(), 0));
97  } else {
98  return flexible_type(flex_vec(v2.size(), 0));
99  }
100  } else if (((v1.get_type() == flex_type_enum::INTEGER) ||
101  (v1.get_type() == flex_type_enum::FLOAT)) &&
102  ((v2.get_type() == flex_type_enum::INTEGER) ||
103  (v2.get_type() == flex_type_enum::FLOAT))) {
104  return flexible_type(0);
105  } else {
106  DASSERT_TRUE(false);
107  }
108  }
109 };
110 
111 class forward_fill: public interpolator_value {
112 
113  public:
114 
115  bool support_type(flex_type_enum type) const {
116  return true;
117  }
118 
119  std::string name() const {
120  return std::string("ffill");
121  }
122 
124  const flexible_type& t2, const flexible_type& v1,
125  const flexible_type& v2) const {
126  return t1 <= t2 ? v1 : v2;
127  }
128 };
129 
130 class nearest : public interpolator_value {
131 
132  public:
133 
134  bool support_type(flex_type_enum type) const {
135  return true;
136  }
137 
138  std::string name() const {
139  return std::string("nearest");
140  }
141 
143  const flexible_type& t2, const flexible_type& v1,
144  const flexible_type& v2) const {
145  size_t del_t1 = t.get<flex_date_time>().posix_timestamp()
146  - t1.get<flex_date_time>().posix_timestamp();
147  size_t del_t2 = t2.get<flex_date_time>().posix_timestamp()
148  - t.get<flex_date_time>().posix_timestamp();
149  return (del_t1 <= del_t2) ? v1 : v2;
150  }
151 };
152 
153 class backward_fill : public interpolator_value {
154 
155  public:
156 
157  bool support_type(flex_type_enum type) const {
158  return true;
159  }
160 
161  std::string name() const {
162  return std::string("bfill");
163  }
164 
166  const flexible_type& t2, const flexible_type& v1,
167  const flexible_type& v2) const {
168  return (t2 >= t1) ? v2 : v1;
169  }
170 };
171 
172 class none_fill: public interpolator_value {
173 
174  public:
175 
176  bool support_type(flex_type_enum type) const {
177  return true;
178  }
179 
180  std::string name() const {
181  return std::string("none");
182  }
183 
185  const flexible_type& t2, const flexible_type& v1,
186  const flexible_type& v2) const {
187  return FLEX_UNDEFINED;
188  }
189 };
190 
191 class linear_interpolation : public interpolator_value {
192 
193  public:
194 
195  bool support_type(flex_type_enum type) const {
196  return (type == flex_type_enum::INTEGER) ||
197  (type == flex_type_enum::FLOAT) ||
198  (type == flex_type_enum::VECTOR);
199  }
200 
201  std::string name() const {
202  return std::string("linear");
203  }
204 
206  const flexible_type& t2, const flexible_type& v1,
207  const flexible_type& v2) const {
208  if ((((v1.get_type() == flex_type_enum::INTEGER) ||
209  (v1.get_type() == flex_type_enum::FLOAT)) &&
210  ((v2.get_type() == flex_type_enum::INTEGER) ||
211  (v2.get_type() == flex_type_enum::FLOAT))) ||
212  ((v1.get_type() == flex_type_enum::VECTOR) &&
213  (v2.get_type() == flex_type_enum::VECTOR))) {
214  const auto& _t = t.get<flex_date_time>();
215  const auto& _t1 = t1.get<flex_date_time>();
216  const auto& _t2 = t2.get<flex_date_time>();
217  int dt_t1 = _t.posix_timestamp() - _t1.posix_timestamp();
218  int dt_21 = _t2.posix_timestamp() - _t1.posix_timestamp();
219  flexible_type scale = double(dt_t1) / dt_21;
220  if (v1.get_type() == flex_type_enum::INTEGER) {
221  return (dt_21 == 0) ? v1: scale * (v2 - v1) + v1; // flex_float
222  } else {
223  return (dt_21 == 0) ? v1: v1 + (v2 - v1) * scale; // type(v1)
224  }
225  }
226  }
227 
228  flex_type_enum set_input_type(flex_type_enum type) {
229  if ((type == flex_type_enum::INTEGER) || (type == flex_type_enum::FLOAT)) {
230  return flex_type_enum::FLOAT;
231  } else if (type == flex_type_enum::VECTOR) {
232  return flex_type_enum::VECTOR;
233  } else {
234  DASSERT_TRUE(false);
235  }
236  }
237 };
238 
239 
240 /**
241  * Helper function to convert string interpolation operators to the built-in
242  * functions.
243  */
244 EXPORT inline std::shared_ptr<interpolator_value> get_builtin_interpolator(const
245  std::string& fill_method) {
246  std::shared_ptr<interpolator_value> interpolation_fn;
247  if (fill_method == "__builtin__zero__") {
248  interpolation_fn.reset(new zero_fill());
249  } else if (fill_method == "__builtin__nearest__") {
250  interpolation_fn.reset(new nearest());
251  } else if (fill_method == "__builtin__ffill__") {
252  interpolation_fn.reset(new forward_fill());
253  } else if (fill_method == "__builtin__bfill__") {
254  interpolation_fn.reset(new backward_fill());
255  } else if (fill_method == "__builtin__none__") {
256  interpolation_fn.reset(new none_fill());
257  } else if (fill_method == "__builtin__linear__") {
258  interpolation_fn.reset(new linear_interpolation());
259  } else {
260  log_and_throw("Internal error. Undefined interpolation method.");
261  }
262  return interpolation_fn;
263 }
264 
265 } // timeseries
266 } // turicreate
267 
268 #endif
std::vector< double > flex_vec
virtual flex_type_enum set_input_types(const std::vector< flex_type_enum > &types)
virtual std::string name() const =0
const T & get() const
flex_type_enum get_type() const
virtual flexible_type interpolate(const flexible_type &t, const flexible_type &t1, const flexible_type &t2, const flexible_type &v1, const flexible_type &v2) const =0
virtual bool support_type(flex_type_enum type) const =0
static flexible_type FLEX_UNDEFINED
#define DASSERT_TRUE(cond)
Definition: assertions.hpp:364