vq3
vq3Epoch.hpp
1 /*
2  * Copyright (C) 2018, CentraleSupelec
3  *
4  * Author : Hervé Frezza-Buet
5  *
6  * Contributor :
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public
10  * License (GPL) as published by the Free Software Foundation; either
11  * version 3 of the License, or any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  *
22  * Contact : herve.frezza-buet@centralesupelec.fr
23  *
24  */
25 
26 
27 
28 #pragma once
29 
30 #include <future>
31 #include <vector>
32 #include <stdexcept>
33 #include <algorithm>
34 #include <set>
35 #include <map>
36 #include <utility>
37 #include <iterator>
38 #include <cmath>
39 
40 #include <vq3Topology.hpp>
41 #include <vq3Utils.hpp>
42 
43 namespace vq3 {
44 
45  namespace spec {
46 
50  template<typename SAMPLE_TYPE, typename VERTEX_VALUE_TYPE, typename PROTOTYPE_TYPE>
51  struct EpochData {
52 
53  using sample_type = SAMPLE_TYPE;
54  using vertex_value_type = VERTEX_VALUE_TYPE;
55  using prototype_type = PROTOTYPE_TYPE;
56 
57  EpochData();
58 
65  void notify_closest(const prototype_type& prototype, const sample_type& sample, double closest_distance);
66 
72  void notify_wtm_update(const sample_type& sample, double topo_coef);
73 
78  void notify_wta_update(const sample_type& sample);
79 
84  void set_prototype(prototype_type& prototype);
85 
90  void set_content(vertex_value_type& vertex_value);
91 
95  EpochData& operator+=(const EpochData& other);
96  };
97  }
98 
99  namespace epoch {
100 
104  template<typename EPOCH_DATA_ITER>
105  auto distortion(const EPOCH_DATA_ITER& begin, const EPOCH_DATA_ITER& end) {
106  if(begin == end)
107  throw std::runtime_error("vq3::epoch::distortion : empty collection");
108  auto it = begin;
109  auto res = it->vq3_bmu_accum;
110  for(++it; it != end; ++it)
111  res += it->vq3_bmu_accum;
112  return res;
113  }
114 
115  namespace data {
116 
120  template<typename SAMPLE_TYPE, typename VERTEX_VALUE_TYPE, typename PROTOTYPE_TYPE>
121  struct none {
122  using sample_type = SAMPLE_TYPE;
123  using vertex_value_type = VERTEX_VALUE_TYPE;
124  using prototype_type = PROTOTYPE_TYPE;
125 
126  none() = default;
127 
128  void notify_closest (const prototype_type&, const sample_type&, double) {}
130 
131  void notify_wtm_update (const sample_type&, double) {}
133 
134  void notify_wta_update (const sample_type&) {}
136 
137  void set_prototype(prototype_type& prototype) {}
139 
140  void set_content(vertex_value_type& vertex_value) {}
142 
143  none& operator+=(const none& other) {return *this;}
144  };
145 
150  template<typename MOTHER>
151  struct wta : MOTHER {
152  using sample_type = typename MOTHER::sample_type;
153  using vertex_value_type = typename MOTHER::vertex_value_type;
154  using prototype_type = typename MOTHER::prototype_type;
155 
157 
158  wta() = default;
159 
160  void notify_closest(const prototype_type& prototype, const sample_type& sample, double dist) {
161  this->MOTHER::notify_closest(prototype, sample, dist);
162  }
164 
165  void notify_wtm_update(const sample_type& sample, double coef) {
166  this->MOTHER::notify_wtm_update(sample, coef);
167  }
169 
170  void notify_wta_update(const sample_type& sample) {
171  this->MOTHER::notify_wta_update(sample);
172  vq3_wta_accum += sample;
173  }
175 
176  void set_prototype(prototype_type& prototype) {
177  this->MOTHER::set_prototype(prototype);
178  if(this->vq3_wta_accum.nb != 0)
179  prototype = this->vq3_wta_accum.template average<double>();
180  }
182 
183  void set_content(vertex_value_type& vertex_value) {
184  this->MOTHER::set_content(vertex_value);
185  }
187 
188  wta<MOTHER>& operator+=(const wta<MOTHER>& arg) {
189  this->MOTHER::operator+=(arg);
190  vq3_wta_accum += arg.vq3_wta_accum;
191  return *this;
192  }
193  };
194 
195 
199  template<typename MOTHER>
200  struct wtm : MOTHER {
201  using sample_type = typename MOTHER::sample_type;
202  using vertex_value_type = typename MOTHER::vertex_value_type;
203  using prototype_type = typename MOTHER::prototype_type;
204 
206 
207 
208  wtm() = default;
209 
210  void notify_closest(const prototype_type& prototype, const sample_type& sample, double dist) {
211  this->MOTHER::notify_closest(prototype, sample, dist);
212  }
214 
215 
216  void notify_wtm_update(const sample_type& sample, double coef) {
217  this->MOTHER::notify_wtm_update(sample, coef);
218  vq3_wtm_accum.increment(coef, sample);
219  }
221 
222 
223  void notify_wta_update(const sample_type& sample) {
224  this->MOTHER::notify_wta_update(sample);
225  }
227 
228  void set_prototype(prototype_type& prototype) {
229  this->MOTHER::set_prototype(prototype);
230  if(vq3_wtm_accum.nb != 0)
231  prototype = vq3_wtm_accum.template average<double>();
232  }
234 
235  void set_content(vertex_value_type& vertex_value) {
236  this->MOTHER::set_content(vertex_value);
237  }
239 
240  wtm<MOTHER>& operator+=(const wtm<MOTHER>& arg) {
241  this->MOTHER::operator+=(arg);
242  vq3_wtm_accum += arg.vq3_wtm_accum;
243  return *this;
244  }
245  };
246 
250  template<typename prototype_type, typename sample_type>
251  struct bmu_dist_accum {
252  double operator()(const prototype_type&, const sample_type&, double d) {return d;}
253  };
254 
258  template<typename prototype_type, typename sample_type>
260  double operator()(const prototype_type&, const sample_type&, double d) {return std::sqrt(d);}
261  };
262 
266  template<typename prototype_type, typename sample_type>
268  double operator()(const prototype_type&, const sample_type&, double d) {return 1.0;}
269  };
270 
271 
276  template<typename MOTHER, typename FCT_ACCUM>
277  struct bmu : MOTHER {
278  using sample_type = typename MOTHER::sample_type;
279  using vertex_value_type = typename MOTHER::vertex_value_type;
280  using prototype_type = typename MOTHER::prototype_type;
281 
283 
284  bmu() = default;
285 
286  void notify_closest(const prototype_type& prototype, const sample_type& sample, double dist) {
287  this->MOTHER::notify_closest(prototype, sample, dist);
288  vq3_bmu_accum += FCT_ACCUM()(prototype, sample, dist);
289  }
291 
292  void notify_wtm_update(const sample_type& sample, double coef) {
293  this->MOTHER::notify_wtm_update(sample, coef);
294  }
296 
297  void notify_wta_update(const sample_type& sample) {
298  this->MOTHER::notify_wta_update(sample);
299  }
301 
302  void set_prototype(prototype_type& prototype) {
303  this->MOTHER::set_prototype(prototype);
304  }
306 
307  void set_content(vertex_value_type& vertex_value) {
308  this->MOTHER::set_content(vertex_value);
309  }
311 
312  bmu<MOTHER, FCT_ACCUM>& operator+=(const bmu<MOTHER, FCT_ACCUM>& arg) {
313  this->MOTHER::operator+=(arg);
314  vq3_bmu_accum += arg.vq3_bmu_accum;
315  return *this;
316  }
317  };
318 
324  template<typename MOTHER>
325  struct delta : MOTHER {
326 
327  using sample_type = typename MOTHER::sample_type;
328  using vertex_value_type = typename MOTHER::vertex_value_type;
329  using prototype_type = typename MOTHER::prototype_type;
330 
331  prototype_type vq3_previous_prototype;
332  prototype_type vq3_current_prototype;
333 
334  delta() = default;
335 
336  void notify_closest(const prototype_type& prototype, const sample_type& sample, double dist) {
337  this->MOTHER::notify_closest(prototype, sample, dist);
338  }
340 
341  void notify_wtm_update(const sample_type& sample, double coef) {
342  this->MOTHER::notify_wtm_update(sample, coef);
343  }
345 
346  void notify_wta_update(const sample_type& sample) {
347  this->MOTHER::notify_wta_update(sample);
348  }
350 
351  void set_prototype(prototype_type& prototype) {
352  vq3_previous_prototype = prototype;
353  this->MOTHER::set_prototype(prototype);
354  vq3_current_prototype = prototype;
355  }
357 
358  void set_content(vertex_value_type& vertex_value) {
359  this->MOTHER::set_content(vertex_value);
360  }
362 
363  delta<MOTHER>& operator+=(const delta<MOTHER>& arg) {
364  this->MOTHER::operator+=(arg);
365  return *this;
366  }
367  };
368 
369  namespace online {
378  template<typename MOTHER>
379  struct bmu_mean_std : MOTHER {
380  using sample_type = typename MOTHER::sample_type;
381  using vertex_value_type = typename MOTHER::vertex_value_type;
382  using prototype_type = typename MOTHER::prototype_type;
383 
385 
386  bmu_mean_std() = default;
387 
388  void notify_closest(const prototype_type& prototype, const sample_type& sample, double dist) {
389  this->MOTHER::notify_closest(prototype, sample, dist);
390  vq3_bmu_accum += dist;
391  }
393 
394  void notify_wtm_update(const sample_type& sample, double coef) {
395  this->MOTHER::notify_wtm_update(sample, coef);
396  }
398 
399  void notify_wta_update(const sample_type& sample) {
400  this->MOTHER::notify_wta_update(sample);
401  }
403 
404  void set_prototype(prototype_type& prototype) {
405  this->MOTHER::set_prototype(prototype);
406  }
408 
409  void set_content(vertex_value_type& vertex_value) {
410  this->MOTHER::set_content(vertex_value);
411  vertex_value.vq3_online_mean_std += vq3_bmu_accum.value;
412  }
414 
415  bmu_mean_std<MOTHER>& operator+=(const bmu_mean_std<MOTHER>& arg) {
416  this->MOTHER::operator+=(arg);
417  vq3_bmu_accum += arg.vq3_bmu_accum;
418  return *this;
419  }
420  };
421  }
422  }
423 
424  namespace chl {
425  template<typename GRAPH, bool WITH_COUNTS>
426  class Processor {
427  private:
428 
429  using graph_type = GRAPH;
430  using ref_vertex = typename graph_type::ref_vertex;
431  using ref_edge = typename graph_type::ref_edge;
432  using edge = typename graph_type::edge_value_type;
433 
434  graph_type& g;
435 
436  struct refpair {
437  ref_vertex first, second;
438  mutable std::size_t chl_count = 0;
439 
440  refpair() = default;
441  refpair(const refpair&) = default;
442  refpair& operator=(const refpair&) = default;
443  refpair(refpair&&) = default;
444  refpair& operator=(refpair&&) = default;
445 
446  refpair(const std::pair<ref_vertex, ref_vertex>& p)
447  : first(p.first), second(p.second) {
448  if(second < first)
449  std::swap(first, second);
450  }
451 
452  bool operator<(const refpair& other) const {
453  return (first < other.first) || ((first == other.first) && (second < other.second));
454  }
455  };
456 
457  struct data {
458  std::set<ref_edge> survivors;
459  std::set<refpair> newedges;
460  data() = default;
461  data(const data&) = default;
462  data& operator=(const data&) = default;
463  data(data&&) = default;
464  data& operator=(data&&) = default;
465  };
466 
467  static auto std_set_union(typename std::vector<refpair>::iterator first1, typename std::vector<refpair>::iterator last1,
468  typename std::set<refpair>::iterator first2, typename std::set<refpair>::iterator last2,
469  std::back_insert_iterator<std::vector<refpair>> d_first,
470  std::vector<refpair>& dest_container) {
471  if constexpr (WITH_COUNTS) {
472  // Slightly modidfied from std::set_union possible implementation given by cppreference.com
473  for (; first1 != last1; ++d_first) {
474  if (first2 == last2)
475  return std::copy(first1, last1, d_first);
476  if (*first2 < *first1) {
477  *d_first = *first2++;
478  } else {
479  // Here *first2 >= *first1
480  *d_first = *first1;
481  if (!(*first1 < *first2)) {// if *first2 <= *first1 (Ideed, *first2 == *first1)
482  // Modification of STL code here
483  dest_container.rbegin()->chl_count += first2->chl_count;
484  ++first2;
485  }
486  ++first1;
487  }
488  }
489  return std::copy(first2, last2, d_first);
490  }
491  else
492  return d_first; // This code is never used...
493  }
494 
495 
496 
497  public:
498 
499  Processor(graph_type& g) : g(g) {}
500  Processor() = delete;
501  Processor(const Processor&) = default;
502  Processor(Processor&&) = default;
503  Processor& operator=(const Processor&) = default;
504  Processor& operator=(Processor&&) = default;
505 
510  template<typename ITERATOR, typename SAMPLE_OF, typename DISTANCE>
511  bool process(unsigned int nb_threads,
512  const ITERATOR& samples_begin, const ITERATOR& samples_end, const SAMPLE_OF& sample_of,
513  const DISTANCE& distance,
514  const edge& value_for_new_edges) {
515  if constexpr (WITH_COUNTS) g.foreach_edge([](auto ref_e) {(*ref_e)().vq3_counter = 0;});
516 
517  auto nb_vertices = g.nb_vertices();
518  if(nb_vertices < 2)
519  return false;
520  if(nb_vertices == 2) {
521  std::array<ref_vertex, 2> vertices;
522  vq3::utils::collect_vertices(g,vertices.begin());
523  auto ref_e = g.get_edge(vertices[0], vertices[1]);
524  if(ref_e == nullptr) {
525  ref_e = g.connect(vertices[0], vertices[1], value_for_new_edges);
526  if constexpr (WITH_COUNTS) ++((*ref_e)().vq3_counter);
527  return true;
528  }
529  return false;
530  }
531 
532  auto iters = utils::split(samples_begin, samples_end, nb_threads);
533  std::vector<std::future<data> > futures;
534  auto out = std::back_inserter(futures);
535 
536  if(nb_threads > 1)
537  g.garbaging_lock();
538 
539  for(auto& begin_end : iters)
540  *(out++) = std::async(std::launch::async,
541  [begin_end, this, &sample_of, &distance]() {
542  data res;
543  for(auto it = begin_end.first; it != begin_end.second; ++it) {
544  auto two = utils::two_closest(g, sample_of(*it), distance);
545  if(two.first && two.second) {
546  auto ref_e = g.get_edge(two.first, two.second);
547  if(ref_e == nullptr) {
548  auto [it, inserted ] = res.newedges.emplace(two);
549  if constexpr (WITH_COUNTS) ++(it->chl_count);
550  }
551  else {
552  if constexpr (WITH_COUNTS) ++((*ref_e)().vq3_counter);
553  res.survivors.emplace(ref_e);
554  }
555  }
556  }
557  return res;
558  });
559 
560  std::vector<ref_edge> survivors;
561  std::vector<refpair> newedges;
562 
563  std::vector<ref_edge> s;
564  std::vector<refpair> n;
565  for(auto& f : futures) {
566  auto d = f.get();
567 
568  s.clear();
569  auto outs = std::back_inserter(s);
570  std::set_union(survivors.begin(), survivors.end(),
571  d.survivors.begin(), d.survivors.end(),
572  outs);
573 
574  n.clear();
575  auto outn = std::back_inserter(n);
576  if constexpr (WITH_COUNTS)
577  std_set_union(newedges.begin(), newedges.end(),
578  d.newedges.begin(), d.newedges.end(),
579  outn, n);
580  else
581  std::set_union(newedges.begin(), newedges.end(),
582  d.newedges.begin(), d.newedges.end(),
583  outn);
584 
585 
586  std::swap(s, survivors);
587  std::swap(n, newedges);
588  }
589 
590  if(nb_threads > 1)
591  g.garbaging_unlock();
592 
593  bool one_kill = false;
594 
595  // Let us remove non surviving edges.
596  utils::clear_edge_tags(g, true);
597  for(auto& ref_e : survivors) (*ref_e)().vq3_tag = false;
598  g.foreach_edge([&one_kill](const ref_edge& ref_e) {
599  if((*ref_e)().vq3_tag) {
600  ref_e->kill();
601  one_kill = true;
602  }
603  });
604 
605  // Let us add the new edges.
606  for(auto& p : newedges) {
607  auto ref_e = g.connect(p.first, p.second, value_for_new_edges);
608  if constexpr (WITH_COUNTS) (*ref_e)().vq3_counter = p.chl_count;
609  }
610 
611  return newedges.size() != 0 || one_kill;
612  }
613  };
614 
615  template<typename GRAPH>
616  auto processor(GRAPH& g) {return Processor<GRAPH, false>(g);}
617 
618  template<typename GRAPH>
619  auto processor_with_counts(GRAPH& g) {return Processor<GRAPH, true>(g);}
620  }
621 
622  namespace count {
623  namespace vertices {
624 
625  template<typename GRAPH>
626  class Processor {
627  private:
628 
629  using graph_type = GRAPH;
630  using ref_vertex = typename graph_type::ref_vertex;
631  graph_type& g;
632 
633  public:
634 
635  Processor(graph_type& g) : g(g) {}
636  Processor() = delete;
637  Processor(const Processor&) = default;
638  Processor(Processor&&) = default;
639  Processor& operator=(const Processor&) = default;
640  Processor& operator=(Processor&&) = default;
641 
647  template<typename ITERATOR, typename SAMPLE_OF, typename MATTERS>
648  void process(unsigned int nb_threads,
649  const ITERATOR& samples_begin, const ITERATOR& samples_end, const SAMPLE_OF& sample_of,
650  const MATTERS& matters) {
651 
652  auto iters = utils::split(samples_begin, samples_end, nb_threads);
653  std::vector<std::thread> threads;
654 
655  if(nb_threads > 1)
656  g.garbaging_lock();
657 
658  for(auto& [begin, end] : iters)
659  threads.emplace_back([begin, end, this, &sample_of, &matters](){
660  for(auto it = begin; it != end; ++it)
661  g.foreach_vertex([&sample_of, &matters, it](auto ref_v) {
662  if(matters(ref_v, sample_of(*it))) (*ref_v)().vq3_counter++;
663  });
664  });
665 
666  for(auto& t : threads) t.join();
667 
668  if(nb_threads > 1)
669  g.garbaging_unlock();
670  }
671  };
672 
673  template<typename GRAPH>
674  auto processor(GRAPH& g) {return Processor<GRAPH>(g);}
675 
676  }
677 
678  namespace edges {
679 
680  template<typename GRAPH>
681  class Processor {
682  private:
683 
684  using graph_type = GRAPH;
685  using ref_edge = typename graph_type::ref_edge;
686  graph_type& g;
687 
688  public:
689 
690  Processor(graph_type& g) : g(g) {}
691  Processor() = delete;
692  Processor(const Processor&) = default;
693  Processor(Processor&&) = default;
694  Processor& operator=(const Processor&) = default;
695  Processor& operator=(Processor&&) = default;
696 
702  template<typename ITERATOR, typename SAMPLE_OF, typename MATTERS>
703  void process(unsigned int nb_threads,
704  const ITERATOR& samples_begin, const ITERATOR& samples_end, const SAMPLE_OF& sample_of,
705  const MATTERS& matters) {
706 
707  auto iters = utils::split(samples_begin, samples_end, nb_threads);
708  std::vector<std::thread> threads;
709 
710  if(nb_threads > 1)
711  g.garbaging_lock();
712 
713  for(auto& [begin, end] : iters)
714  threads.emplace_back([begin, end, this, &sample_of, &matters](){
715  for(auto it = begin; it != end; ++it)
716  g.foreach_edge([&sample_of, &matters, it](auto ref_e) {
717  auto extr_pair = ref_e->extremities();
718  if(vq3::invalid_extremities(extr_pair)) {
719  ref_e->kill(); // Ok, garbaging is locked.
720  return;
721  }
722  if(matters(ref_e, sample_of(*it))) (*ref_e)().vq3_counter++;
723  });
724  });
725 
726  for(auto& t : threads) t.join();
727 
728  if(nb_threads > 1)
729  g.garbaging_unlock();
730  }
731  };
732 
733  template<typename GRAPH>
734  auto processor(GRAPH& g) {return Processor<GRAPH>(g);}
735 
736  }
737 
738 
739 
740 
741  }
742 
743  namespace wta {
744 
745  template<typename TABLE>
746  class Processor {
747  public:
748 
749  using topology_table_type = TABLE;
750 
751  private:
752 
753  topology_table_type& table;
754 
755  public:
756 
757  Processor(topology_table_type& table) : table(table) {}
758  Processor() = delete;
759  Processor(const Processor&) = delete;
760  Processor(Processor&&) = default;
761  Processor& operator=(const Processor&) = delete;
762  Processor& operator=(Processor&&) = delete;
763 
764 
768  template<typename EPOCH_DATA, typename ITERATOR, typename SAMPLE_OF, typename PROTOTYPE_OF_VERTEX_VALUE, typename DISTANCE>
769  auto process(unsigned int nb_threads, const ITERATOR& samples_begin, const ITERATOR& samples_end, const SAMPLE_OF& sample_of, const PROTOTYPE_OF_VERTEX_VALUE& prototype_of, const DISTANCE& distance) {
770  auto iters = utils::split(samples_begin, samples_end, nb_threads);
771  std::vector<std::future<std::vector<EPOCH_DATA> > > futures;
772  auto out = std::back_inserter(futures);
773 
774  if(nb_threads > 1)
775  table.g.garbaging_lock();
776 
777  for(auto& begin_end : iters)
778  *(out++) = std::async(std::launch::async,
779  [begin_end, this, &sample_of, &distance, &prototype_of]() {
780  std::vector<EPOCH_DATA> data(table.size());
781  for(auto it = begin_end.first; it != begin_end.second; ++it) {
782  double min_dist;
783  const auto& sample = sample_of(*it);
784  auto closest = utils::closest(table.g, sample, distance, min_dist);
785  if(closest) {
786  auto& d = data[table(closest)];
787  d.notify_closest(prototype_of((*closest)()), sample, min_dist);
788  d.notify_wta_update(sample);
789  }
790  }
791  return data;
792  });
793 
794  auto fit = futures.begin();
795  if(futures.end() != fit) {
796  auto data0 = (fit++)->get();
797  auto b0 = data0.begin();
798  auto e0 = data0.end();
799  for(unsigned int thread_id = 1; thread_id < nb_threads; ++thread_id) {
800  auto datai = (fit++)->get();
801  auto bi = datai.begin();
802  for(auto b = b0; b != e0; ++b, ++bi)
803  (*b) += *bi;
804  }
805 
806  if(nb_threads > 1)
807  table.g.garbaging_unlock();
808 
809  unsigned int idx = 0;
810  for(auto& d : data0) {
811  auto& value = (*(table(idx++)))();
812  d.set_prototype(prototype_of(value));
813  d.set_content(value);
814  }
815 
816  return data0;
817  }
818  else {
819  if(nb_threads > 1)
820  table.g.garbaging_unlock();
821  return std::vector<EPOCH_DATA>();
822  }
823  }
824  };
825 
826  template<typename TABLE>
827  auto processor(TABLE& table) {return Processor<TABLE>(table);}
828  }
829 
830  namespace wtm {
831 
832  template<typename TABLE>
833  class Processor {
834  public:
835 
836  using topology_table_type = TABLE;
837 
838  private:
839 
840  topology_table_type& table;
841 
842  public:
843 
844 
845  Processor(topology_table_type& table) : table(table) {}
846  Processor() = delete;
847  Processor(const Processor&) = delete;
848  Processor(Processor&&) = default;
849  Processor& operator=(const Processor&) = delete;
850  Processor& operator=(Processor&&) = delete;
851 
852 
856  template<typename EPOCH_DATA, typename ITERATOR, typename SAMPLE_OF, typename PROTOTYPE_OF_VERTEX_VALUE, typename DISTANCE>
857  auto process(unsigned int nb_threads,
858  const typename topology_table_type::neighborhood_key_type& neighborhood_key,
859  const ITERATOR& samples_begin, const ITERATOR& samples_end, const SAMPLE_OF& sample_of, const PROTOTYPE_OF_VERTEX_VALUE& prototype_of, const DISTANCE& distance) {
860  auto iters = utils::split(samples_begin, samples_end, nb_threads);
861  std::vector<std::future<std::vector<EPOCH_DATA> > > futures;
862  auto out = std::back_inserter(futures);
863 
864  if(nb_threads > 1)
865  table.g.garbaging_lock();
866 
867  for(auto& begin_end : iters)
868  *(out++) = std::async(std::launch::async,
869  [begin_end, this, &sample_of, &distance, size = table.size(), &neighborhood_key, &prototype_of]() {
870  std::vector<EPOCH_DATA> data(size);
871  for(auto it = begin_end.first; it != begin_end.second; ++it) {
872  double min_dist;
873  const auto& sample = sample_of(*it);
874  auto closest = utils::closest(table.g, sample, distance, min_dist);
875  if(closest) {
876  auto& neighborhood = table.neighborhood(closest, neighborhood_key);
877  data[neighborhood.begin()->index].notify_closest(prototype_of((*closest)()), sample, min_dist);
878  for(auto& info : neighborhood) data[info.index].notify_wtm_update(sample, info.value);
879  }
880  }
881  return data;
882  });
883 
884  auto fit = futures.begin();
885  if(fit != futures.end()) {
886  auto data0 = (fit++)->get();
887  auto b0 = data0.begin();
888  auto e0 = data0.end();
889  for(unsigned int thread_id = 1; thread_id < nb_threads; ++thread_id) {
890  auto datai = (fit++)->get();
891  auto bi = datai.begin();
892  for(auto b = b0; b != e0; ++b, ++bi)
893  (*b) += *bi;
894  }
895 
896  if(nb_threads > 1)
897  table.g.garbaging_unlock();
898 
899  unsigned int idx = 0;
900  for(auto& d : data0) {
901  auto& value = (*(table(idx++)))();
902  d.set_prototype(prototype_of(value));
903  d.set_content(value);
904  }
905  return data0;
906  }
907  else {
908  if(nb_threads > 1)
909  table.g.garbaging_unlock();
910  return std::vector<EPOCH_DATA>();
911  }
912  }
913  };
914 
915  template<typename TABLE>
916  auto processor(TABLE& table) {return Processor<TABLE>(table);}
917  }
918  }
919 }
vq3::epoch::count::edges::Processor
Definition: vq3Epoch.hpp:681
vq3::spec::EpochData::notify_closest
void notify_closest(const prototype_type &prototype, const sample_type &sample, double closest_distance)
vq3::epoch::wta::Processor
Definition: vq3Epoch.hpp:746
vq3::epoch::data::wtm
Definition: vq3Epoch.hpp:200
vq3::epoch::data::delta::vq3_previous_prototype
prototype_type vq3_previous_prototype
The vertex value computed at the previous step.
Definition: vq3Epoch.hpp:331
vq3::spec::EpochData::set_prototype
void set_prototype(prototype_type &prototype)
vq3::epoch::chl::Processor
Definition: vq3Epoch.hpp:426
vq3::spec::EpochData::operator+=
EpochData & operator+=(const EpochData &other)
vq3::spec::EpochData::notify_wta_update
void notify_wta_update(const sample_type &sample)
vq3::spec::EpochData::notify_wtm_update
void notify_wtm_update(const sample_type &sample, double topo_coef)
vq3::spec::EpochData::set_content
void set_content(vertex_value_type &vertex_value)
vq3::epoch::data::bmu::vq3_bmu_accum
utils::accum< double, double > vq3_bmu_accum
The sum of distortions when the nodes is the BMU.
Definition: vq3Epoch.hpp:282
vq3::epoch::data::online::bmu_mean_std::vq3_bmu_accum
vq3::utils::accum< double, double > vq3_bmu_accum
The sum of distortions when the nodes is the BMU.
Definition: vq3Epoch.hpp:384
vq3::epoch::data::wta
Definition: vq3Epoch.hpp:151
vq3::epoch::count::vertices::Processor::process
void process(unsigned int nb_threads, const ITERATOR &samples_begin, const ITERATOR &samples_end, const SAMPLE_OF &sample_of, const MATTERS &matters)
Definition: vq3Epoch.hpp:648
vq3::epoch::data::bmu
Definition: vq3Epoch.hpp:277
vq3::epoch::data::delta
Definition: vq3Epoch.hpp:325
vq3::epoch::wtm::Processor::process
auto process(unsigned int nb_threads, const typename topology_table_type::neighborhood_key_type &neighborhood_key, const ITERATOR &samples_begin, const ITERATOR &samples_end, const SAMPLE_OF &sample_of, const PROTOTYPE_OF_VERTEX_VALUE &prototype_of, const DISTANCE &distance)
Definition: vq3Epoch.hpp:857
vq3::epoch::data::bmu_dist_accum
Definition: vq3Epoch.hpp:251
vq3::epoch::data::delta::vq3_current_prototype
prototype_type vq3_current_prototype
The vertex value computed at the current step.
Definition: vq3Epoch.hpp:332
vq3::epoch::count::edges::Processor::process
void process(unsigned int nb_threads, const ITERATOR &samples_begin, const ITERATOR &samples_end, const SAMPLE_OF &sample_of, const MATTERS &matters)
Definition: vq3Epoch.hpp:703
vq3::epoch::data::wta::vq3_wta_accum
utils::accum< sample_type, double > vq3_wta_accum
The sum of samples in the Voronoï cell.
Definition: vq3Epoch.hpp:156
vq3::spec::EpochData
Definition: vq3Epoch.hpp:51
vq3::utils::accum::increment
accum & increment(NB_TYPE coef, const INCREMENTABLE &v)
Definition: vq3Utils.hpp:89
vq3::epoch::data::online::bmu_mean_std
Definition: vq3Epoch.hpp:379
vq3::utils::accum< sample_type, double >
vq3::epoch::data::bmu_count_accum
Definition: vq3Epoch.hpp:267
vq3::epoch::data::none
Definition: vq3Epoch.hpp:121
vq3::epoch::wtm::Processor
Definition: vq3Epoch.hpp:833
vq3::epoch::wta::Processor::process
auto process(unsigned int nb_threads, const ITERATOR &samples_begin, const ITERATOR &samples_end, const SAMPLE_OF &sample_of, const PROTOTYPE_OF_VERTEX_VALUE &prototype_of, const DISTANCE &distance)
Definition: vq3Epoch.hpp:769
vq3::epoch::count::vertices::Processor
Definition: vq3Epoch.hpp:626
vq3::epoch::data::bmu_sqrt_dist_accum
Definition: vq3Epoch.hpp:259
vq3::epoch::data::wtm::vq3_wtm_accum
utils::accum< sample_type, double > vq3_wtm_accum
The weighted sum of samples in the Voronoï cell.
Definition: vq3Epoch.hpp:205
vq3::epoch::chl::Processor::process
bool process(unsigned int nb_threads, const ITERATOR &samples_begin, const ITERATOR &samples_end, const SAMPLE_OF &sample_of, const DISTANCE &distance, const edge &value_for_new_edges)
Definition: vq3Epoch.hpp:511