vq3
vq3Utils.hpp
1 
2 /*
3  * Copyright (C) 2018, CentraleSupelec
4  *
5  * Author : HervĂ© Frezza-Buet
6  *
7  * Contributor :
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public
11  * License (GPL) as published by the Free Software Foundation; either
12  * version 3 of the License, or any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  *
23  * Contact : herve.frezza-buet@centralesupelec.fr
24  *
25  */
26 
27 #pragma once
28 
29 #include <limits>
30 #include <utility>
31 #include <vector>
32 #include <optional>
33 #include <list>
34 #include <map>
35 #include <stack>
36 #include <type_traits>
37 #include <iterator>
38 #include <algorithm>
39 #include <stdexcept>
40 #include <iostream>
41 #include <sstream>
42 #include <iomanip>
43 
44 #include <vq3Graph.hpp>
45 
46 namespace vq3 {
47 
48  namespace error {
49  struct empty_accumulation : public std::runtime_error {
50  using std::runtime_error::runtime_error;
51  };
52  }
53 
54  namespace utils {
55 
56  template<typename INCREMENTABLE, typename NB_TYPE>
57  struct accum {
58  NB_TYPE nb;
59  INCREMENTABLE value;
60 
61  accum(const accum&) = default;
62  accum& operator=(const accum&) = default;
63  accum(accum&&) = default;
64  accum& operator=(accum&&) = default;
65 
66  accum() : nb(0), value() {}
67 
72  template<typename NB_AVG_TYPE = NB_TYPE>
73  auto average() const {return value/static_cast<NB_AVG_TYPE>(nb);}
74 
75  void clear() {
76  nb = 0;
77  value = INCREMENTABLE();
78  }
79 
82  accum& operator=(const INCREMENTABLE& v) {
83  nb = 1;
84  value = v;
85  return *this;
86  }
87 
89  accum& increment(NB_TYPE coef, const INCREMENTABLE& v) {
90  nb += coef;
91  value += coef * v;
92  return *this;
93  }
94 
96  accum& operator+=(const INCREMENTABLE& v) {
97  ++nb;
98  value += v;
99  return *this;
100  }
101 
103  accum& operator+=(const accum& a) {
104  nb += a.nb;
105  value += a.value;
106  return *this;
107  }
108  };
109 
110 
116  template<typename GRAPH, typename VALUE_OF_REF_VERTEX>
117  auto make_vertex_table(GRAPH& g, const VALUE_OF_REF_VERTEX& value_of) {
118  std::map<typename GRAPH::ref_vertex, typename std::result_of<VALUE_OF_REF_VERTEX (typename GRAPH::ref_vertex)>::type> res;
119  g.foreach_vertex([&res, &value_of](const typename GRAPH::ref_vertex& ref_v) {res[ref_v] = value_of(ref_v);});
120  return res;
121  }
122 
128  template<typename GRAPH, typename OUTPUT_IT>
129  void collect_vertices(GRAPH& g, const OUTPUT_IT& outit) {
130  auto out = outit;
131  g.foreach_vertex([&out](const typename GRAPH::ref_vertex& ref_v) {*(out++) = ref_v;});
132  }
133 
139  template<typename GRAPH, typename OUTPUT_IT>
140  void collect_edges(GRAPH& g, const OUTPUT_IT& outit) {
141  auto out = outit;
142  g.foreach_edge([&out](const typename GRAPH::ref_edge& ref_e) {
143  auto extr = ref_e->extremities();
144  if(invalid_extremities(extr))
145  ref_e->kill();
146  else
147  *(out++) = ref_e;});
148  }
149 
153  template<typename PROCESS, typename = void>
155  void operator()(const PROCESS& d) const {}
156  };
157 
161  template<typename PROCESS>
162  struct execute_vq3_closest_init_if_available<PROCESS, decltype(std::declval<PROCESS>().vq3_closest_init())> {
163  void operator()(const PROCESS& d) const {d.vq3_closest_init();}
164  };
165 
174  template<typename GRAPH, typename SAMPLE, typename DISTANCE>
175  typename GRAPH::ref_vertex closest(GRAPH& g, const SAMPLE& sample, const DISTANCE& distance, double& closest_distance_value) {
176  typename GRAPH::ref_vertex res = nullptr;
177  double dist = std::numeric_limits<double>::max();
179  g.foreach_vertex([&dist, &res, &sample, &distance](const typename GRAPH::ref_vertex& ref_v) {
180  if(double d = distance((*ref_v)(), sample); d < dist) {
181  dist = d;
182  res = ref_v;
183  }
184 
185  });
186  closest_distance_value = dist;
187  return res;
188  }
189 
197  template<typename GRAPH, typename SAMPLE, typename DISTANCE>
198  typename GRAPH::ref_vertex closest(GRAPH& g, const SAMPLE& sample, const DISTANCE& distance) {
199  double d;
200  return closest(g, sample, distance, d);
201  }
202 
211  template<typename GRAPH, typename SAMPLE, typename DISTANCE>
212  typename std::pair<typename GRAPH::ref_vertex, typename GRAPH::ref_vertex> two_closest(GRAPH& g, const SAMPLE& sample, const DISTANCE& distance, std::pair<double, double>& closest_distance_values) {
213  std::pair<typename GRAPH::ref_vertex, typename GRAPH::ref_vertex> res = {nullptr, nullptr};
214  double dist1 = std::numeric_limits<double>::max();
215  double dist2 = std::numeric_limits<double>::max();
216  execute_vq3_closest_init_if_available<DISTANCE>()(distance);
217  g.foreach_vertex([&dist1, &dist2, &res, &sample, &distance](const typename GRAPH::ref_vertex& ref_v) {
218  double d = distance((*ref_v)(), sample);
219  if(d < dist1) {
220  dist2 = dist1;
221  res.second = res.first;
222  dist1 = d;
223  res.first = ref_v;
224  }
225  else if(d < dist2) {
226  dist2 = d;
227  res.second = ref_v;
228  }
229  });
230  closest_distance_values = {dist1, dist2};
231  return res;
232  }
233 
234 
242  template<typename GRAPH, typename SAMPLE, typename DISTANCE>
243  typename std::pair<typename GRAPH::ref_vertex, typename GRAPH::ref_vertex> two_closest(GRAPH& g, const SAMPLE& sample, const DISTANCE& distance) {
244  std::pair<double, double> dists;
245  return two_closest(g, sample, distance, dists);
246  }
247 
256  template<typename GRAPH, typename SAMPLE, typename DISTANCE>
257  typename GRAPH::ref_edge closest_edge(GRAPH& g, const SAMPLE& sample, const DISTANCE& distance, double& closest_distance_value) {
258  typename GRAPH::ref_edge res = nullptr;
259  double dist = std::numeric_limits<double>::max();
260  execute_vq3_closest_init_if_available<DISTANCE>()(distance);
261  g.foreach_edge([&dist, &res, &sample, &distance](const typename GRAPH::ref_edge& ref_e) {
262  auto extr = ref_e->extremities();
263  if(invalid_extremities(extr))
264  ref_e->kill();
265  else if(double d = distance((*(extr.first))(), (*(extr.second))(), sample); d < dist) {
266  dist = d;
267  res = ref_e;
268  }
269  });
270  closest_distance_value = dist;
271  return res;
272  }
273 
281  template<typename GRAPH, typename SAMPLE, typename DISTANCE>
282  typename GRAPH::ref_edge closest_edge(GRAPH& g, const SAMPLE& sample, const DISTANCE& distance) {
283  double dist;
284  return closest_edge(g, sample, distance, dist);
285  }
286 
297  template<typename GRAPH, typename VERTEX_VALUE_OF, typename EDGE_VALUE_OF>
298  auto make_grid(GRAPH& g, unsigned int width, unsigned int height,
299  const VERTEX_VALUE_OF& v_of, const EDGE_VALUE_OF& e_of,
300  bool loop_w = false, bool loop_h = false) {
301  std::vector<std::vector<typename GRAPH::ref_vertex>> lines;
302  std::vector<typename GRAPH::ref_vertex> line(width);
303  auto lout = std::back_inserter(lines);
304 
305  unsigned int w, h;
306  unsigned int width_ = width - 1;
307  unsigned int height_ = height - 1;
308 
309  for(h = 0; h < height; ++h) {
310  for(w = 0; w < width; ++w)
311  line[w] = (g += v_of(w, h));
312  *(lout++) = line;
313  }
314 
315  for(h = 0; h < height_; ++h) {
316  for(w = 0; w < width_; ++w) {
317  g.connect(lines[h][w], lines[h][w + 1], e_of(w, h, w + 1, h));
318  g.connect(lines[h][w], lines[h + 1][w], e_of(w, h, w, h + 1));
319  }
320  g.connect(lines[h][w], lines[h + 1][w], e_of(w, h, w, h + 1));
321  }
322  for(w = 0; w < width_; ++w)
323  g.connect(lines[h][w], lines[h][w + 1], e_of(w, h, w + 1, h));
324 
325  if(loop_w && width > 1)
326  for(h = 0; h < height; ++h)
327  g.connect(lines[h][0], lines[h][width_], e_of(0, h, width_, h));
328 
329  if(loop_h && height > 1)
330  for(w = 0; w < width; ++w)
331  g.connect(lines[0][w], lines[height_][w], e_of(w, 0, w, height_));
332 
333 
334  return lines;
335  }
336 
337 
347  template<typename GRAPH, typename VERTEX_VALUE_OF>
348  auto make_grid(GRAPH& g, unsigned int width, unsigned int height,
349  const VERTEX_VALUE_OF& v_of,
350  bool loop_w = false, bool loop_h = false) {
351  std::vector<std::vector<typename GRAPH::ref_vertex>> lines;
352  std::vector<typename GRAPH::ref_vertex> line(width);
353  auto lout = std::back_inserter(lines);
354 
355  unsigned int w, h;
356  unsigned int width_ = width - 1;
357  unsigned int height_ = height - 1;
358 
359  for(h = 0; h < height; ++h) {
360  for(w = 0; w < width; ++w)
361  line[w] = (g += v_of(w, h));
362  *(lout++) = line;
363  }
364 
365  for(h = 0; h < height_; ++h) {
366  for(w = 0; w < width_; ++w) {
367  g.connect(lines[h][w], lines[h][w + 1]);
368  g.connect(lines[h][w], lines[h + 1][w]);
369  }
370  g.connect(lines[h][w], lines[h + 1][w]);
371  }
372  for(w = 0; w < width_; ++w)
373  g.connect(lines[h][w], lines[h][w + 1]);
374 
375  if(loop_w && width > 1)
376  for(h = 0; h < height; ++h)
377  g.connect(lines[h][0], lines[h][width_]);
378 
379  if(loop_h && height > 1)
380  for(w = 0; w < width; ++w)
381  g.connect(lines[0][w], lines[height_][w]);
382 
383  return lines;
384  }
385 
389  template<typename GRAPH>
390  void clear_vertex_tags(GRAPH& g, bool value) {
391  g.foreach_vertex([value](const typename GRAPH::ref_vertex& ref_v) {(*ref_v)().vq3_tag = value;});
392  }
393 
397  template<typename GRAPH>
398  void clear_edge_tags(GRAPH& g, bool value) {
399  g.foreach_edge([value](const typename GRAPH::ref_edge& ref_e) {
400  auto extr = ref_e->extremities();
401  if(invalid_extremities(extr))
402  ref_e->kill();
403  else
404  (*ref_e)().vq3_tag = value;
405  });
406  }
407 
411  template<typename GRAPH>
412  void clear_all_tags(GRAPH& g, bool value) {
413  clear_vertex_tags(g, value);
414  clear_edge_tags(g, value);
415  }
416 
420  template<typename GRAPH>
421  void clear_vertex_counters(GRAPH& g, std::size_t value) {
422  g.foreach_vertex([value](const typename GRAPH::ref_vertex& ref_v) {(*ref_v)().vq3_counter = value;});
423  }
424 
428  template<typename GRAPH>
429  void clear_edge_counters(GRAPH& g, std::size_t value) {
430  g.foreach_edge([value](const typename GRAPH::ref_edge& ref_e) {
431  auto extr = ref_e->extremities();
432  if(invalid_extremities(extr))
433  ref_e->kill();
434  else
435  (*ref_e)().vq3_counter = value;
436  });
437  }
438 
442  template<typename GRAPH>
443  void clear_all_counters(GRAPH& g, std::size_t value) {
444  clear_vertex_counters(g, value);
445  clear_edge_counters(g, value);
446  }
447 
448 
452  template<typename GRAPH>
453  void clear_vertex_labels(GRAPH& g, unsigned int value) {
454  g.foreach_vertex([value](const typename GRAPH::ref_vertex& ref_v) {(*ref_v)().vq3_label = value;});
455  }
456 
460  template<typename GRAPH>
461  void clear_edge_labels(GRAPH& g, unsigned int value) {
462  g.foreach_edge([value](const typename GRAPH::ref_edge& ref_e) {
463  auto extr = ref_e->extremities();
464  if(invalid_extremities(extr))
465  ref_e->kill();
466  else
467  (*ref_e)().vq3_label = value;
468  });
469  }
470 
474  template<typename GRAPH>
475  void clear_all_labels(GRAPH& g, unsigned int value) {
476  clear_vertex_labels(g, value);
477  clear_edge_labels(g, value);
478  }
479 
483  template<typename GRAPH>
484  void clear_vertex_efficiencies(GRAPH& g, bool value) {
485  g.foreach_vertex([value](const typename GRAPH::ref_vertex& ref_v) {(*ref_v)().vq3_efficient = value;});
486  }
487 
491  template<typename GRAPH>
492  void clear_edge_efficiencies(GRAPH& g, bool value) {
493  g.foreach_edge([value](const typename GRAPH::ref_edge& ref_e) {
494  auto extr = ref_e->extremities();
495  if(invalid_extremities(extr))
496  ref_e->kill();
497  else
498  (*ref_e)().vq3_efficient = value;
499  });
500  }
501 
505  template<typename GRAPH>
506  void clear_all_efficiencies(GRAPH& g, bool value) {
507  clear_vertex_efficiencies(g, value);
508  clear_edge_efficiencies(g, value);
509  }
510 
515  template<typename IT>
516  auto split(const IT& begin, const IT& end, unsigned int nb) {
517  std::vector< std::pair<IT, IT> > pairs;
518  pairs.reserve(nb);
519  auto out = std::back_inserter(pairs);
520  auto coef = std::distance(begin, end)/double(nb);
521  unsigned int q = 0;
522  IT last = begin;
523  IT it = begin;
524  for(unsigned int i = 1; i <= nb; ++i) {
525  auto first = last;
526  auto p = q;
527  q = (unsigned int)(i*coef+.5);
528  std::advance(it, q-p);
529  last = it;
530  *(out++) = {first, last};
531  }
532  return pairs;
533  }
534 
535 
539  template<typename REF_VERTEX, typename EDGE_FUN>
540  void foreach_efficient_edge(const REF_VERTEX& ref_v, const EDGE_FUN& fun) {
541  ref_v->foreach_edge([fun](const typename REF_VERTEX::element_type::ref_edge_type& ref_e) {
542  if((*ref_e)().vq3_efficient)
543  fun(ref_e);
544  });
545  }
546 
547 
548  namespace savitzky_golay {
549 
553  template<typename VALUE, unsigned int ORDER, unsigned int WINDOW_SIZE>
554  class Estimator {
555  protected:
556 
557  std::deque<VALUE> window;
558  mutable std::array<std::optional<VALUE>, ORDER+1> value; // value[i] is the ith order derivative... optional since it may not be available.
559 
560  public:
561 
562  Estimator() = default;
563  Estimator(const Estimator&) = default;
564  Estimator(Estimator&&) = default;
565  Estimator& operator=(const Estimator&) = default;
566  Estimator& operator=(Estimator&&) = default;
567 
571  void operator+=(const VALUE& v) {
572  window.emplace_back(v);
573  if(window.size() > WINDOW_SIZE)
574  window.pop_front();
575  for(auto& v : value) v.reset();
576  }
577 
581  template<unsigned int O>
582  const std::optional<VALUE>& get() const {
583  static_assert(O <= ORDER, "vq3::utils::savitzky_golay::get<O> : O is too high.");
584  return value[O];
585  }
586  };
587 
588  namespace constant_timestep {
589 
590  template<unsigned int ORDER, unsigned int WINDOW_SIZE, unsigned int DEGREE>
591  struct sg_norm {
592  // We use "ORDER < 0" instead of "false" to make the static
593  // assert dependent on T. Otherwise, the compilation failure
594  // occurs systematically.
595  static_assert(ORDER < 0, "The parameters passed to vq3::utils::savitzky_golay::constant_timestep::estimator<...> leads to an unimplemented case (sg_norm fails).");
596  };
597 
598  template<typename VALUE, unsigned int ORDER, unsigned int WINDOW_SIZE, unsigned int DEGREE>
599  struct sg_compute {
600  // We use "ORDER < 0" instead of "false" to make the static
601  // assert dependent on T. Otherwise, the compilation failure
602  // occurs systematically.
603  static_assert(ORDER < 0, "The parameters passed to vq3::utils::savitzky_golay::constant_timestep::estimator<...> leads to an unimplemented case (sg_compute fails).");
604  };
605 
606  // The coefficients are obtained from Robert Mellet's web page.
607  // http://robert.mellet.pagesperso-orange.fr/rgrs_pol/regrs_06.htm
608 
609  //
610  // win = 9, degree = 2.
611  //
612 
613  template<> struct sg_norm<0, 9, 2> {double value; sg_norm(double) {value = 1/231.0;}};
614  template<typename VALUE> struct sg_compute<VALUE, 0, 9, 2> {
615  VALUE value;
616  template<typename ITER>
617  sg_compute(ITER iter) {
618  value = (*(iter++)) * -21;
619  value += (*(iter++)) * 14;
620  value += (*(iter++)) * 39;
621  value += (*(iter++)) * 54;
622  value += (*(iter++)) * 59;
623  value += (*(iter++)) * 54;
624  value += (*(iter++)) * 39;
625  value += (*(iter++)) * 14;
626  value += (*(iter++)) * -21;
627  }
628  };
629 
630  template<> struct sg_norm<1, 9, 2> {double value; sg_norm(double step) {value = 1/(60*step);}};
631  template<typename VALUE> struct sg_compute<VALUE, 1, 9, 2> {
632  VALUE value;
633  template<typename ITER>
634  sg_compute(ITER iter) {
635  value = (*(iter++)) * -4;
636  value += (*(iter++)) * -3;
637  value += (*(iter++)) * -2;
638  value += (*(iter++)) * -1;
639  ++iter;
640  value += (*(iter++)) * 1;
641  value += (*(iter++)) * 2;
642  value += (*(iter++)) * 3;
643  value += (*(iter++)) * 4;
644  }
645  };
646 
647  template<> struct sg_norm<2, 9, 2> {double value; sg_norm(double step) {value = 1/(462*step*step);}};
648  template<typename VALUE> struct sg_compute<VALUE, 2, 9, 2> {
649  VALUE value;
650  template<typename ITER>
651  sg_compute(ITER iter) {
652  value = (*(iter++)) * 28;
653  value += (*(iter++)) * 7;
654  value += (*(iter++)) * -8;
655  value += (*(iter++)) * -17;
656  value += (*(iter++)) * -20;
657  value += (*(iter++)) * -17;
658  value += (*(iter++)) * -8;
659  value += (*(iter++)) * 7;
660  value += (*(iter++)) * 28;
661  }
662  };
663 
664 
665  //
666  // win = 15, degree = 2.
667  //
668 
669  template<> struct sg_norm<0, 15, 2> {double value; sg_norm(double) {value = 1/1105.0;}};
670  template<typename VALUE> struct sg_compute<VALUE, 0, 15, 2> {
671  VALUE value;
672  template<typename ITER>
673  sg_compute(ITER iter) {
674  value = (*(iter++)) * -78;
675  value += (*(iter++)) * -13;
676  value += (*(iter++)) * 42;
677  value += (*(iter++)) * 87;
678  value += (*(iter++)) * 122;
679  value += (*(iter++)) * 147;
680  value += (*(iter++)) * 162;
681  value += (*(iter++)) * 167;
682  value += (*(iter++)) * 162;
683  value += (*(iter++)) * 147;
684  value += (*(iter++)) * 122;
685  value += (*(iter++)) * 87;
686  value += (*(iter++)) * 42;
687  value += (*(iter++)) * -13;
688  value += (*(iter++)) * -78;
689  }
690  };
691 
692  template<> struct sg_norm<1, 15, 2> {double value; sg_norm(double step) {value = 1/(280*step);}};
693  template<typename VALUE> struct sg_compute<VALUE, 1, 15, 2> {
694  VALUE value;
695  template<typename ITER>
696  sg_compute(ITER iter) {
697  value = (*(iter++)) * -7;
698  value += (*(iter++)) * -6;
699  value += (*(iter++)) * -5;
700  value += (*(iter++)) * -4;
701  value += (*(iter++)) * -3;
702  value += (*(iter++)) * -2;
703  value += (*(iter++)) * -1;
704  ++iter;
705  value += (*(iter++)) * 1;
706  value += (*(iter++)) * 2;
707  value += (*(iter++)) * 3;
708  value += (*(iter++)) * 4;
709  value += (*(iter++)) * 5;
710  value += (*(iter++)) * 6;
711  value += (*(iter++)) * 7;
712  }
713  };
714 
715  template<> struct sg_norm<2, 15, 2> {double value; sg_norm(double step) {value = 1/(6188*step*step);}};
716  template<typename VALUE> struct sg_compute<VALUE, 2, 15, 2> {
717  VALUE value;
718  template<typename ITER>
719  sg_compute(ITER iter) {
720  value = (*(iter++)) * 91;
721  value += (*(iter++)) * 52;
722  value += (*(iter++)) * 19;
723  value += (*(iter++)) * -8;
724  value += (*(iter++)) * -29;
725  value += (*(iter++)) * -44;
726  value += (*(iter++)) * -53;
727  value += (*(iter++)) * -56;
728  value += (*(iter++)) * -53;
729  value += (*(iter++)) * -44;
730  value += (*(iter++)) * -29;
731  value += (*(iter++)) * -8;
732  value += (*(iter++)) * 19;
733  value += (*(iter++)) * 52;
734  value += (*(iter++)) * 91;
735  }
736  };
737 
738  //
739  // win = 21, degree = 2.
740  //
741 
742  template<> struct sg_norm<0, 21, 2> {double value; sg_norm(double) {value = 1/3059.0;}};
743  template<typename VALUE> struct sg_compute<VALUE, 0, 21, 2> {
744  VALUE value;
745  template<typename ITER>
746  sg_compute(ITER iter) {
747  value = (*(iter++)) * -171;
748  value += (*(iter++)) * -76;
749  value += (*(iter++)) * 9;
750  value += (*(iter++)) * 84;
751  value += (*(iter++)) * 149;
752  value += (*(iter++)) * 204;
753  value += (*(iter++)) * 249;
754  value += (*(iter++)) * 284;
755  value += (*(iter++)) * 309;
756  value += (*(iter++)) * 324;
757  value += (*(iter++)) * 329;
758  value += (*(iter++)) * 324;
759  value += (*(iter++)) * 309;
760  value += (*(iter++)) * 284;
761  value += (*(iter++)) * 249;
762  value += (*(iter++)) * 204;
763  value += (*(iter++)) * 149;
764  value += (*(iter++)) * 84;
765  value += (*(iter++)) * 9;
766  value += (*(iter++)) * -76;
767  value += (*(iter++)) * -171;
768  }
769  };
770 
771  template<> struct sg_norm<1, 21, 2> {double value; sg_norm(double step) {value = 1/(770*step);}};
772  template<typename VALUE> struct sg_compute<VALUE, 1, 21, 2> {
773  VALUE value;
774  template<typename ITER>
775  sg_compute(ITER iter) {
776  value = (*(iter++)) * -11;
777  value += (*(iter++)) * -10;
778  value += (*(iter++)) * -9;
779  value += (*(iter++)) * -7;
780  value += (*(iter++)) * -6;
781  value += (*(iter++)) * -5;
782  value += (*(iter++)) * -4;
783  value += (*(iter++)) * -3;
784  value += (*(iter++)) * -2;
785  value += (*(iter++)) * -1;
786  ++iter;
787  value += (*(iter++)) * 1;
788  value += (*(iter++)) * 2;
789  value += (*(iter++)) * 3;
790  value += (*(iter++)) * 4;
791  value += (*(iter++)) * 5;
792  value += (*(iter++)) * 6;
793  value += (*(iter++)) * 7;
794  value += (*(iter++)) * 9;
795  value += (*(iter++)) * 10;
796  value += (*(iter++)) * 11;
797  }
798  };
799 
800 
801  template<> struct sg_norm<2, 21, 2> {double value; sg_norm(double step) {value = 1/(33649*step*step);}};
802  template<typename VALUE> struct sg_compute<VALUE, 2, 21, 2> {
803  VALUE value;
804  template<typename ITER>
805  sg_compute(ITER iter) {
806  value = (*(iter++)) * 190;
807  value += (*(iter++)) * 133;
808  value += (*(iter++)) * 82;
809  value += (*(iter++)) * 37;
810  value += (*(iter++)) * -2;
811  value += (*(iter++)) * -35;
812  value += (*(iter++)) * -62;
813  value += (*(iter++)) * -83;
814  value += (*(iter++)) * -98;
815  value += (*(iter++)) * -107;
816  value += (*(iter++)) * -110;
817  value += (*(iter++)) * -107;
818  value += (*(iter++)) * -98;
819  value += (*(iter++)) * -83;
820  value += (*(iter++)) * -62;
821  value += (*(iter++)) * -35;
822  value += (*(iter++)) * -2;
823  value += (*(iter++)) * 37;
824  value += (*(iter++)) * 82;
825  value += (*(iter++)) * 133;
826  value += (*(iter++)) * 190;
827  }
828  };
829 
830  //
831  // win = 21, degree = 3.
832  //
833 
834  template<> struct sg_norm<0, 21, 3> {double value; sg_norm(double step) {value = sg_norm<0, 21, 2>(step).value;}};
835  template<typename VALUE> struct sg_compute<VALUE, 0, 21, 3> {
836  VALUE value;
837  template<typename ITER>
838  sg_compute(ITER iter) {
839  value = sg_compute<VALUE, 0, 21, 2>(iter).value;
840  }
841  };
842 
843  template<> struct sg_norm<1, 21, 3> {double value; sg_norm(double step) {value = 1/(3634092*step);}};
844  template<typename VALUE> struct sg_compute<VALUE, 1, 21, 3> {
845  VALUE value;
846  template<typename ITER>
847  sg_compute(ITER iter) {
848  value = (*(iter++)) * 84075;
849  value += (*(iter++)) * 10032;
850  value += (*(iter++)) * -43284;
851  value += (*(iter++)) * -78176;
852  value += (*(iter++)) * -96947;
853  value += (*(iter++)) * -101900;
854  value += (*(iter++)) * -95338;
855  value += (*(iter++)) * -79654;
856  value += (*(iter++)) * -56881;
857  value += (*(iter++)) * -29592;
858  ++iter;
859  value += (*(iter++)) * 29592;
860  value += (*(iter++)) * 56881;
861  value += (*(iter++)) * 79654;
862  value += (*(iter++)) * 95338;
863  value += (*(iter++)) * 101900;
864  value += (*(iter++)) * 96947;
865  value += (*(iter++)) * 78176;
866  value += (*(iter++)) * 43284;
867  value += (*(iter++)) * -10032;
868  value += (*(iter++)) * -84075;
869  }
870  };
871 
872  template<> struct sg_norm<2, 21, 3> {double value; sg_norm(double step) {value = sg_norm<2, 21, 2>(step).value;}};
873  template<typename VALUE> struct sg_compute<VALUE, 2, 21, 3> {
874  VALUE value;
875  template<typename ITER>
876  sg_compute(ITER iter) {
877  value = sg_compute<VALUE, 2, 21, 2>(iter).value;
878  }
879  };
880 
881 
882 
883  //
884  // Estimator
885  //
886 
887  template<typename VALUE, unsigned int ORDER, unsigned int WINDOW_SIZE, unsigned int DEGREE>
888  class estimator : public savitzky_golay::Estimator<VALUE, ORDER, WINDOW_SIZE> {
889  private:
890  std::array<double, ORDER+1> hcoef;
891 
892  template<unsigned int O>
893  void __set_timestep(double step) {
894  if constexpr (O == 0)
895  hcoef[0] = sg_norm<0, WINDOW_SIZE, DEGREE>(step).value;
896  else {
897  hcoef[O] = sg_norm<O, WINDOW_SIZE, DEGREE>(step).value;
898  __set_timestep<O-1>(step);
899  }
900  }
901 
902  public:
903 
905 
909  void set_timestep(double step) {
910  __set_timestep<ORDER>(step);
911  }
912 
916  template<unsigned int O>
917  const std::optional<VALUE>& get() const {
918  static_assert(O <= ORDER, "vq3::utils::savitzky_golay::get<O> : O is too high.");
919  auto& v = this->value[O];
920  if(!v && this->window.size() == WINDOW_SIZE)
921  v = sg_compute<VALUE, O, WINDOW_SIZE, DEGREE>(this->window.begin()).value * hcoef[O];
922  return v;
923  }
924  };
925  }
926  }
927 
928 
929 
930  }
931 }
vq3::utils::savitzky_golay::constant_timestep::estimator::get
const std::optional< VALUE > & get() const
Definition: vq3Utils.hpp:917
vq3::utils::savitzky_golay::constant_timestep::sg_compute< VALUE, 0, 21, 2 >
Definition: vq3Utils.hpp:743
vq3::utils::savitzky_golay::constant_timestep::estimator
Definition: vq3Utils.hpp:888
vq3::utils::execute_vq3_closest_init_if_available
Definition: vq3Utils.hpp:154
vq3::utils::accum::average
auto average() const
Definition: vq3Utils.hpp:73
vq3::utils::accum::operator=
accum & operator=(const INCREMENTABLE &v)
Definition: vq3Utils.hpp:82
vq3::utils::savitzky_golay::constant_timestep::sg_norm
Definition: vq3Utils.hpp:591
vq3::utils::savitzky_golay::constant_timestep::sg_compute
Definition: vq3Utils.hpp:599
vq3::error::empty_accumulation
Definition: vq3Utils.hpp:49
vq3::utils::savitzky_golay::Estimator
Definition: vq3Utils.hpp:554
vq3::utils::savitzky_golay::constant_timestep::sg_compute< VALUE, 2, 21, 2 >
Definition: vq3Utils.hpp:802
vq3::utils::accum::operator+=
accum & operator+=(const accum &a)
Definition: vq3Utils.hpp:103
vq3::utils::savitzky_golay::constant_timestep::estimator::set_timestep
void set_timestep(double step)
Definition: vq3Utils.hpp:909
vq3::utils::savitzky_golay::Estimator::operator+=
void operator+=(const VALUE &v)
Definition: vq3Utils.hpp:571
vq3::utils::accum::increment
accum & increment(NB_TYPE coef, const INCREMENTABLE &v)
Definition: vq3Utils.hpp:89
vq3::utils::accum
Definition: vq3Utils.hpp:57
vq3::utils::savitzky_golay::Estimator::get
const std::optional< VALUE > & get() const
Definition: vq3Utils.hpp:582
vq3::utils::savitzky_golay::constant_timestep::sg_norm< 0, 21, 2 >
Definition: vq3Utils.hpp:742
vq3::utils::savitzky_golay::constant_timestep::sg_norm< 2, 21, 2 >
Definition: vq3Utils.hpp:801
vq3::utils::accum::operator+=
accum & operator+=(const INCREMENTABLE &v)
Definition: vq3Utils.hpp:96