pf
resamplers.h
Go to the documentation of this file.
1 #ifndef RESAMPLERS_H
2 #define RESAMPLERS_H
3 
4 #include <chrono>
5 #include <array>
6 #include <random>
7 #include <numeric> // accumulate, partial_sum
8 #include <cmath> //floor
9 
10 #ifdef DROPPINGTHISINRPACKAGE
11  #include <RcppEigen.h>
12  // [[Rcpp::depends(RcppEigen)]]
13 #else
14  #include <Eigen/Dense>
15 #endif
16 
17 #include <algorithm> // sort
18 #include <bitset> // bitset
19 
20 #include "rv_eval.h" // for rveval::evalUnivStdNormCDF<float_t>()
21 
22 
23 namespace pf {
24 
25 namespace resamplers {
26 
27 
28 
30 
41 template<size_t nparts, size_t dimx, typename float_t >
42 class rbase
43 {
44 public:
45 
47  using ssv = Eigen::Matrix<float_t,dimx,1>;
49  using arrayVec = std::array<ssv, nparts>;
51  using arrayFloat = std::array<float_t,nparts>;
52 
53 
57  rbase();
58 
59 
64  rbase(unsigned long seed);
65 
66 
72  virtual void resampLogWts(arrayVec &oldParts, arrayFloat &oldLogUnNormWts) = 0;
73 
74 protected:
75 
77  std::mt19937 m_gen;
78 
79 };
80 
81 
82 template<size_t nparts, size_t dimx, typename float_t>
84  : m_gen{static_cast<std::uint32_t>(
85  std::chrono::high_resolution_clock::now().time_since_epoch().count()
86  )}
87 {
88 }
89 
90 
91 template<size_t nparts, size_t dimx, typename float_t>
93  : m_gen{static_cast<std::uint32_t>(seed)}
94 {
95 }
96 
97 
98 
108 template<size_t nparts, size_t dimx, typename float_t>
109 class mn_resampler : private rbase<nparts, dimx, float_t>
110 {
111 public:
112 
114  using ssv = Eigen::Matrix<float_t,dimx,1>;
116  using arrayVec = std::array<ssv, nparts>;
118  using arrayFloat = std::array<float_t,nparts>;
120  using arrayInt = std::array<unsigned int,nparts>;
121 
125  mn_resampler() = default;
126 
127 
132  mn_resampler(unsigned long seed);
133 
134 
140  void resampLogWts(arrayVec &oldParts, arrayFloat &oldLogUnNormWts);
141 
142 };
143 
144 
145 template<size_t nparts, size_t dimx, typename float_t>
147  : rbase<nparts, dimx, float_t>(seed)
148 {
149 }
150 
151 
152 template<size_t nparts, size_t dimx, typename float_t>
154 {
155  // these log weights may be very negative. If that's the case, exponentiating them may cause underflow
156  // so we use the "log-exp-sum" trick
157  // actually not quite...we just shift the log-weights because after they're exponentiated
158  // they have the same normalized probabilities
159 
160  // Create the distribution with exponentiated log-weights
161  arrayFloat w;
162  float_t m = *std::max_element(oldLogUnNormWts.begin(), oldLogUnNormWts.end());
163  std::transform(oldLogUnNormWts.begin(), oldLogUnNormWts.end(), w.begin(),
164  [&m](float_t& d) -> float_t { return std::exp( d - m ); } );
165  std::discrete_distribution<> idxSampler(w.begin(), w.end());
166 
167  // create temporary particle vector and weight vector
168  arrayVec tmpPartics = oldParts;
169 
170  // sample from the original parts and store in tmpParts
171  unsigned int whichPart;
172  for(size_t part = 0; part < nparts; ++part)
173  {
174  whichPart = idxSampler(this->m_gen);
175  tmpPartics[part] = oldParts[whichPart];
176  }
177 
178  //overwrite olds with news
179  oldParts = std::move(tmpPartics);
180  std::fill(oldLogUnNormWts.begin(), oldLogUnNormWts.end(), 0.0); // change back
181 }
182 
183 
184 
195 template<size_t nparts, size_t dimsampledx, typename cfModT, typename float_t>
197 {
198 public:
199 
201  using ssv = Eigen::Matrix<float_t,dimsampledx,1>;
203  using arrayVec = std::array<ssv, nparts>;
205  using arrayFloat = std::array<float_t,nparts>;
207  using arrayMod = std::array<cfModT,nparts>;
208 
213 
214 
218  mn_resampler_rbpf(unsigned long seed);
219 
220 
227  void resampLogWts(arrayMod &oldMods, arrayVec &oldParts, arrayFloat &oldLogUnNormWts);
228 
229 
230 private:
231 
233  std::mt19937 m_gen;
234 };
235 
236 
237 template<size_t nparts, size_t dimsampledx, typename cfModT, typename float_t>
239  : m_gen{static_cast<std::uint32_t>(
240  std::chrono::high_resolution_clock::now().time_since_epoch().count()
241  )}
242 {
243 }
244 
245 
246 template<size_t nparts, size_t dimsampledx, typename cfModT, typename float_t>
248  : m_gen{ static_cast<std::uint32_t>(seed) }
249 {
250 }
251 
252 
253 template<size_t nparts, size_t dimsampledx, typename cfModT, typename float_t>
255 {
256  // Create the distribution with exponentiated log-weights
257  arrayFloat w;
258  float_t m = *std::max_element(oldLogUnNormWts.begin(), oldLogUnNormWts.end());
259  std::transform(oldLogUnNormWts.begin(), oldLogUnNormWts.end(), w.begin(),
260  [&m](float_t& d) -> float_t { return std::exp( d - m ); } );
261  std::discrete_distribution<> idxSampler(w.begin(), w.end());
262 
263  // create temporary vectors for samps and mods
264  arrayVec tmpSamps;
265  arrayMod tmpMods;
266 
267  // sample from the original parts and store in temporary
268  unsigned int whichPart;
269  for(size_t part = 0; part < nparts; ++part)
270  {
271  whichPart = idxSampler(m_gen);
272  tmpSamps[part] = oldSamps[whichPart];
273  tmpMods[part] = oldMods[whichPart];
274  }
275 
276  //overwrite olds with news
277  oldMods = std::move(tmpMods);
278  oldSamps = std::move(tmpSamps);
279  std::fill(oldLogUnNormWts.begin(), oldLogUnNormWts.end(), 0.0);
280 
281 }
282 
283 
294 template<size_t nparts, size_t dimx, typename float_t>
295 class resid_resampler : private rbase<nparts, dimx, float_t>
296 {
297 public:
298 
300  using ssv = Eigen::Matrix<float_t,dimx,1>;
302  using arrayVec = std::array<ssv, nparts>;
304  using arrayFloat = std::array<float_t,nparts>;
306  using arrayInt = std::array<unsigned int, nparts>;
307 
308 
312  resid_resampler() = default;
313 
314 
319  resid_resampler(unsigned long seed);
320 
321 
327  void resampLogWts(arrayVec &oldParts, arrayFloat &oldLogUnNormWts);
328 
329 };
330 
331 
332 template<size_t nparts, size_t dimx, typename float_t>
334  : rbase<nparts, dimx, float_t>(seed)
335 {
336 }
337 
338 
339 template<size_t nparts, size_t dimx, typename float_t>
341 {
342 
343  // calculate normalized weights
344  arrayFloat w;
345  float_t m = *std::max_element(oldLogUnNormWts.begin(), oldLogUnNormWts.end());
346  std::transform(oldLogUnNormWts.begin(), oldLogUnNormWts.end(), w.begin(),
347  [&m](const float_t& d) -> float_t { return std::exp( d - m ); } );
348  float_t norm_const (0.0);
349  norm_const = std::accumulate(w.begin(), w.end(), norm_const);
350  for( auto& weight : w)
351  weight = weight/norm_const;
352 
353  // calc unNormWBars and numRandomSamples (N-R using IIHMM notation)
354  size_t i;
355  arrayFloat unNormWBar;
356  float_t numRandomSamples(0.0);
357  for(i = 0; i < nparts; ++i) {
358  unNormWBar[i] = w[i]*nparts - std::floor(w[i]*nparts);
359  numRandomSamples += unNormWBar[i];
360  }
361 
362  // make multinomial distribution for residuals
363  std::discrete_distribution<> idxSampler(unNormWBar.begin(), unNormWBar.end());
364 
365  // start resampling by producing a count vector
366  arrayInt sampleCounts;
367  for(i = 0; i < nparts; ++i) {
368  sampleCounts[i] = static_cast<unsigned int>(std::floor(nparts*w[i])); // initial
369  }
370  for(i = 0; i < static_cast<unsigned int>(numRandomSamples); ++i) {
371  sampleCounts[idxSampler(this->m_gen)]++;
372  }
373 
374  // now resample the particles using the counts
375  arrayVec tmpPartics;
376  unsigned int c(0);
377  for(i = 0; i < nparts; ++i) { // over count container
378  unsigned int num_replicants = sampleCounts[i];
379  if( num_replicants > 0) {
380  for(size_t j = 0; j < num_replicants; ++j) { // assign the same thing several times
381  tmpPartics[c] = oldParts[i];
382  c++;
383  }
384  }
385  }
386 
387  //overwrite olds with news
388  oldParts = std::move(tmpPartics);
389  std::fill(oldLogUnNormWts.begin(), oldLogUnNormWts.end(), 0.0); // change back
390 }
391 
392 
403 template<size_t nparts, size_t dimx, typename float_t>
404 class stratif_resampler : private rbase<nparts, dimx, float_t>
405 {
406 public:
407 
409  using ssv = Eigen::Matrix<float_t,dimx,1>;
411  using arrayVec = std::array<ssv, nparts>;
413  using arrayFloat = std::array<float_t,nparts>;
415  using arrayInt = std::array<unsigned int, nparts>;
416 
417 
421  stratif_resampler() = default;
422 
423 
428  stratif_resampler(unsigned long seed);
429 
430 
436  void resampLogWts(arrayVec &oldParts, arrayFloat &oldLogUnNormWts);
437 
438 };
439 
440 
441 template<size_t nparts, size_t dimx, typename float_t>
443  : rbase<nparts, dimx, float_t>(seed)
444 {
445 }
446 
447 
448 template<size_t nparts, size_t dimx, typename float_t>
450 {
451 
452  // calculate normalized weights
453  arrayFloat w;
454  float_t m = *std::max_element(oldLogUnNormWts.begin(), oldLogUnNormWts.end());
455  std::transform(oldLogUnNormWts.begin(), oldLogUnNormWts.end(), w.begin(),
456  [&m](const float_t& d) -> float_t { return std::exp( d - m ); } );
457  float_t norm_const (0.0);
458  norm_const = std::accumulate(w.begin(), w.end(), norm_const);
459  for( auto& weight : w)
460  weight = weight/norm_const;
461 
462  // calculate the cumulative sums of the weights
463  arrayFloat cumsums;
464  std::partial_sum(w.begin(), w.end(), cumsums.begin());
465 
466  // samplethe Uis
467  std::uniform_real_distribution<float_t> u_sampler(0.0, 1.0/nparts);
468  arrayFloat u_samples;
469  for(size_t i = 0; i < nparts; ++i) {
470  u_samples[i] = i/nparts + u_sampler(this->m_gen);
471  }
472 
473  // resample
474  arrayVec tmpPartics;
475  for(size_t i = 0; i < nparts; ++i){ // tmpPartics, Uis
476 
477  // find which index
478  unsigned int idx;
479  for(unsigned int j = 0; j < nparts; ++j){
480 
481  // get the first time it gets covered by a cumsum
482  if(cumsums[j] >= u_samples[i]){
483  idx = j;
484  break;
485  }
486  }
487 
488  // assign
489  tmpPartics[i] = oldParts[idx];
490  }
491 
492  //overwrite olds with news
493  oldParts = std::move(tmpPartics);
494  std::fill(oldLogUnNormWts.begin(), oldLogUnNormWts.end(), 0.0); // change back
495 }
496 
497 
508 template<size_t nparts, size_t dimx, typename float_t>
509 class systematic_resampler : private rbase<nparts, dimx, float_t>
510 {
511 public:
512 
514  using ssv = Eigen::Matrix<float_t,dimx,1>;
516  using arrayVec = std::array<ssv, nparts>;
518  using arrayFloat = std::array<float_t,nparts>;
520  using arrayInt = std::array<unsigned int, nparts>;
521 
522 
526  systematic_resampler() = default;
527 
528 
533  systematic_resampler(unsigned long seed);
534 
535 
541  void resampLogWts(arrayVec &oldParts, arrayFloat &oldLogUnNormWts);
542 
543 };
544 
545 
546 template<size_t nparts, size_t dimx, typename float_t>
548  : rbase<nparts, dimx, float_t>(seed)
549 {
550 }
551 
552 
553 template<size_t nparts, size_t dimx, typename float_t>
555 {
556 
557  // calculate normalized weights
558  arrayFloat w;
559  float_t m = *std::max_element(oldLogUnNormWts.begin(), oldLogUnNormWts.end());
560  std::transform(oldLogUnNormWts.begin(), oldLogUnNormWts.end(), w.begin(),
561  [&m](const float_t& d) -> float_t { return std::exp( d - m ); } );
562  float_t norm_const (0.0);
563  norm_const = std::accumulate(w.begin(), w.end(), norm_const);
564  for( auto& weight : w)
565  weight = weight/norm_const;
566 
567  // calculate the cumulative sums of the weights
568  arrayFloat cumsums;
569  std::partial_sum(w.begin(), w.end(), cumsums.begin());
570 
571  // samplethe Uis
572  std::uniform_real_distribution<float_t> u_sampler(0.0, 1.0/nparts);
573  arrayFloat u_samples;
574  u_samples[0] = u_sampler(this->m_gen);
575  for(size_t i = 1; i < nparts; ++i) {
576  u_samples[i] = u_samples[i-1] + 1.0/nparts;
577  }
578 
579  // resample
580  // unlike stratified, take advantage of U's being sorted
581  arrayVec tmpPartics;
582  unsigned idx;
583  unsigned int j = 0;
584  for(size_t i = 0; i < nparts; ++i){ // tmpPartics, Uis
585 
586  // find which index
587  while(j < nparts){
588 
589  // get the first time it gets covered by a cumsum
590  if(cumsums[j] >= u_samples[i]){
591  idx = j;
592  break;
593  }
594 
595  j++;
596  }
597 
598  // assign
599  tmpPartics[i] = oldParts[idx];
600  }
601 
602  //overwrite olds with news
603  oldParts = std::move(tmpPartics);
604  std::fill(oldLogUnNormWts.begin(), oldLogUnNormWts.end(), 0.0); // change back
605 }
606 
607 
617 template<size_t nparts, size_t dimx, typename float_t>
618 class mn_resamp_fast1 : private rbase<nparts, dimx, float_t>
619 {
620 public:
621 
623  using ssv = Eigen::Matrix<float_t,dimx,1>;
625  using arrayVec = std::array<ssv, nparts>;
627  using arrayFloat = std::array<float_t,nparts>;
629  using arrayInt = std::array<unsigned int,nparts>;
630 
634  mn_resamp_fast1() = default;
635 
636 
640  mn_resamp_fast1(unsigned long seed);
641 
642 
648  void resampLogWts(arrayVec &oldParts, arrayFloat &oldLogUnNormWts);
649 
650 };
651 
652 
653 template<size_t nparts, size_t dimx, typename float_t>
655  : rbase<nparts, dimx, float_t>(seed)
656 {
657 }
658 
659 
660 template<size_t nparts, size_t dimx, typename float_t>
662 {
663  // these log weights may be very negative. If that's the case, exponentiating them may cause underflow
664  // so we use the "log-exp-sum" trick
665  // actually not quite...we just shift the log-weights because after they're exponentiated
666  // they have the same normalized probabilities
667 
668  // Also, we're using a fancier algorthm detailed on page 244 of IHMM
669 
670  // Create unnormalized weights
671  arrayFloat unnorm_weights;
672  float_t m = *std::max_element(oldLogUnNormWts.begin(), oldLogUnNormWts.end());
673  std::transform(oldLogUnNormWts.begin(), oldLogUnNormWts.end(), unnorm_weights.begin(),
674  [&m](float_t& d) -> float_t { return std::exp( d - m ); } );
675 
676  // get a uniform rv sampler
677  std::uniform_real_distribution<float_t> u_sampler(0.0, 1.0);
678 
679  // two things:
680  // 1.) calculate normalizing constant for weights, and
681  // 2.) generate all these exponentials to help with getting order statistics
682  // NB: you never need to store E_{N+1}! (this is subtle)
683  float_t weight_norm_const(0.0);
684  arrayFloat exponentials;
685  float_t G(0.0);
686  for(size_t i = 0; i < nparts; ++i) {
687  weight_norm_const += unnorm_weights[i];
688  exponentials[i] = -std::log(u_sampler(this->m_gen));
689  G += exponentials[i];
690  }
691  G -= std::log(u_sampler(this->m_gen)); // E_{N+1}
692 
693  // see Fig 7.15 in IHMM on page 243
694  arrayVec tmpPartics = oldParts; // the new particles
695  float_t uniform_order_stat(0.0); // U_{(i)} in the notation of IHMM
696  float_t running_sum_normalized_weights(unnorm_weights[0]/weight_norm_const); // \sum_{j=1}^I \omega^j in the notation of IHMM
697  float_t one_less_summand(0.0); // \sum_{j=1}^{I-1} \omega^j
698  unsigned int idx = 0;
699  for(size_t i = 0; i < nparts; ++i){
700  uniform_order_stat += exponentials[i]/G; // add a spacing E_i/G
701  do {
702  if( (one_less_summand < uniform_order_stat) && (uniform_order_stat <= running_sum_normalized_weights) ) {
703  // select index idx
704  tmpPartics[i] = oldParts[idx];
705  break;
706  }else{
707  // increment idx because it will never be chosen (all the other order statistics are even higher)
708  idx++;
709  running_sum_normalized_weights += unnorm_weights[idx]/weight_norm_const;
710  one_less_summand += unnorm_weights[idx-1]/weight_norm_const;
711  }
712  }while(true);
713  }
714 
715  //overwrite olds with news
716  oldParts = std::move(tmpPartics);
717  std::fill(oldLogUnNormWts.begin(), oldLogUnNormWts.end(), 0.0);
718 }
719 
720 
731 template<size_t num_bits, size_t num_dims>
732 std::array<std::bitset<num_bits>,num_dims> TransposeToAxes(std::array<std::bitset<num_bits>,num_dims> X)
733 {
734 
735  using coord_t = std::bitset<num_bits>;
736 
737 
738  // Gray decode by H ^ (H/2)
739  coord_t t = X[num_dims-1] >> 1;
740  for(int i = num_dims-1; i > 0; i-- ) // https://stackoverflow.com/a/10384110
741  X[i] ^= X[i-1];
742  X[0] ^= t;
743 
744  // Undo excess work
745  coord_t N = 2 << (num_bits-1);
746  for( coord_t Q = 2; Q != N; Q <<= 1 ) {
747  coord_t P = Q.to_ulong() - 1;
748  for( int i = num_dims - 1; i >= 0; i--){
749  if( (X[i] & Q).any() ){ // invert low bits of X[0]
750  X[0] ^= P;
751  } else{ // exchange low bits of X[i] and X[0]
752  t = (X[0]^X[i]) & P;
753  X[0] ^= t;
754  X[i] ^= t;
755  }
756  }
757  }
758 
759  return X;
760 }
761 
762 
773 template<size_t num_bits, size_t num_dims>
774 std::array<std::bitset<num_bits>,num_dims> AxesToTranspose(std::array<std::bitset<num_bits>, num_dims> X)
775 {
776  using coord_t = std::bitset<num_bits>;
777 
778  // Inverse undo
779  coord_t M = 1 << (num_bits-1);
780  for( coord_t Q = M; Q.to_ulong() > 1; Q >>= 1 ) {
781  coord_t P = Q.to_ulong() - 1;
782  for(size_t i = 0; i < num_dims; i++ ){
783  if( (X[i] & Q).any() )
784  X[0] ^= P;
785  else{
786  coord_t t = (X[0]^X[i]) & P;
787  X[0] ^= t;
788  X[i] ^= t;
789  }
790  }
791  } // exchange
792 
793  // Gray encode
794  for( size_t i = 1; i < num_dims; i++ )
795  X[i] ^= X[i-1];
796 
797  coord_t t = 0;
798  for( coord_t Q = M; Q.to_ulong() > 1; Q >>= 1 ){
799  if( (X[num_dims-1] & Q).any() )
800  t ^= Q.to_ulong()-1;
801  }
802 
803  for( size_t i = 0; i < num_dims; i++ )
804  X[i] ^= t;
805 
806  return X;
807 }
808 
809 
821 template<size_t num_bits, size_t num_dims>
822 std::array<std::bitset<num_bits>,num_dims> makeHTranspose(unsigned int H)
823 {
824  using coord_t = std::bitset<num_bits>;
825  using coords_t = std::array<coord_t, num_dims>;
826  using big_coord_t = std::bitset<num_bits*num_dims>;
827 
828  big_coord_t Hb = H;
829  coords_t X;
830  for(size_t dim = 0; dim < num_dims; ++dim){
831 
832  coord_t dim_coord_tmp;
833  unsigned start_bit = num_bits*num_dims-1-dim;
834  unsigned int c = num_bits - 1;
835  for(int bit = start_bit; bit >= 0; bit -= num_dims){
836  dim_coord_tmp[c] = Hb[bit];
837  c--;
838  }
839  X[dim] = dim_coord_tmp;
840  }
841  return X;
842 }
843 
844 
856 template<size_t num_bits, size_t num_dims>
857 unsigned int makeH(std::array<std::bitset<num_bits>,num_dims> Htrans)
858 {
859  using big_coord_t = std::bitset<num_bits*num_dims>;
860 
861  big_coord_t H;
862  unsigned int which_dim = 0;
863  unsigned which_bit;
864  for(int i = num_bits*num_dims - 1; i >= 0; i--){
865  which_bit = i / num_dims;
866  H[i] = Htrans[which_dim][which_bit];
867  which_dim = (which_dim + 1) % num_dims;
868  }
869  return H.to_ulong();
870 
871 }
872 
873 
875 
887 template<size_t nparts, size_t dimx, size_t dimur, size_t num_hilb_bits, typename float_t >
889 {
890 public:
891 
893  using ssv = Eigen::Matrix<float_t,dimx,1>;
895  using arrayVec = std::array<ssv, nparts>;
897  using arrayFloat = std::array<float_t,nparts>;
899  using usvr = Eigen::Matrix<float_t,dimur,1>;
900 
904  rbase_hcs() = default;
905 
906 
913  virtual void resampLogWts(arrayVec &oldParts, arrayFloat &oldLogUnNormWts, const usvr& ur) = 0;
914 
915 private:
916 
921  static bool hilbertComparison(const ssv& first, const ssv& second);
922 
923 public:
924 
930  std::array<unsigned, nparts> get_permutation(const arrayVec& unsortedParts);
931 
932 };
933 
934 
935 template<size_t nparts, size_t dimx, size_t dimur, size_t num_hilb_bits, typename float_t>
937 {
938  // return true if first "<" second
939  // three intermediate steps to do that:
940  // 1.
941  // squash each vector's elements from
942  // (-infty,infty) -> [0, 2^num_hilb_bits)
943  // with the function
944  // f(x) = 2^num_bits/(1 + e^{-x}) = 2^{num_bits - 1} + 2^{num_bits - 1}*tanh(x/2)
945  float_t c = std::pow(2, num_hilb_bits - 1);
946  ssv squashed_first = first * .5;
947  squashed_first = squashed_first.array().tanh()*c + c ;
948  ssv squashed_second = second * .5;
949  squashed_second = squashed_second.array().tanh()*c + c;
950 
951  // 2.
952  // convert the squashed matrix into bitset type obj"
953  std::array<std::bitset<num_hilb_bits>, dimx> axes_first;
954  std::array<std::bitset<num_hilb_bits>, dimx> axes_second;
955  for(size_t dim = 0; dim < dimx; ++dim){
956  axes_first[dim] = static_cast<unsigned int>(std::floor(squashed_first(dim)));
957  axes_second[dim] = static_cast<unsigned int>(std::floor(squashed_second(dim)));
958  }
959 
960  // 3.
961  // convert to one dimensional unsigned using "AxesToTranspose" and "makeH"
962  return makeH(AxesToTranspose(axes_first)) < makeH(AxesToTranspose(axes_second));
963 }
964 
965 
966 template<size_t nparts, size_t dimx, size_t dimur, size_t num_hilb_bits, typename float_t>
967 std::array<unsigned,nparts> rbase_hcs<nparts,dimx,dimur,num_hilb_bits,float_t>::get_permutation(const arrayVec &unsortedParts)
968 {
969  // create unsorted index
970  std::array<unsigned,nparts> indexes;
971  for(unsigned i = 0; i < nparts; ++i)
972  indexes[i] = i;
973 
974  // create functor to help sort indexes based on particle samples (not weights)
975  struct sort_indexes{
976 
977  arrayVec m_unsorted_parts;
978 
979  sort_indexes(const arrayVec& prts) : m_unsorted_parts(prts) {};
980 
981  bool operator()(unsigned i, unsigned j) const {
982  return rbase_hcs<nparts,dimx,dimur,num_hilb_bits,float_t>::hilbertComparison(m_unsorted_parts[i], m_unsorted_parts[j]);
983  }
984  };
985 
986  // sort the indexes and return them
987  std::sort(indexes.begin(), indexes.end(), sort_indexes(unsortedParts));
988  return indexes;
989 }
990 
991 
1002 template<size_t nparts, size_t dimx, size_t num_hilb_bits, typename float_t>
1003 class sys_hilb_resampler : private rbase_hcs<nparts, dimx, 1, num_hilb_bits, float_t>
1004 {
1005 public:
1006 
1008  using ssv = Eigen::Matrix<float_t,dimx,1>;
1010  using arrayVec = std::array<ssv, nparts>;
1012  using arrayFloat = std::array<float_t,nparts>;
1014  using arrayInt = std::array<unsigned int, nparts>;
1016  using usvr = Eigen::Matrix<float_t,1,1>;
1017 
1021  sys_hilb_resampler() = default;
1022 
1023 
1030  void resampLogWts(arrayVec &oldParts, arrayFloat &oldLogUnNormWts, const usvr& ur);
1031 
1032 };
1033 
1034 
1035 template<size_t nparts, size_t dimx, size_t num_hilb_bits, typename float_t>
1037 {
1038  // calculate normalized weights
1039  arrayFloat w;
1040  float_t m = *std::max_element(oldLogUnNormWts.begin(), oldLogUnNormWts.end());
1041  std::transform(oldLogUnNormWts.begin(), oldLogUnNormWts.end(), w.begin(),
1042  [&m](const float_t& d) -> float_t { return std::exp( d - m ); } );
1043  float_t norm_const (0.0);
1044  norm_const = std::accumulate(w.begin(), w.end(), norm_const);
1045  for( auto& weight : w)
1046  weight = weight/norm_const;
1047 
1048  // samplethe Ubar_tis
1049  arrayFloat ubar_samples;
1050  ubar_samples[0] = rveval::evalUnivStdNormCDF<float_t>(ur(0))/nparts;
1051  for(size_t i = 1; i < nparts; ++i) {
1052  ubar_samples[i] = ubar_samples[i-1] + 1.0/nparts;
1053  }
1054 
1055  // calculate the cumulative sums of the sorted weights
1056  // calculate sorted particles while you're at it
1057  auto sigmaPermutation = this->get_permutation(oldParts);
1058  arrayFloat sortedWeights;
1059  arrayVec sortedParts;
1060  for(size_t i = 0; i < nparts; ++i){
1061  unsigned sigma_i = sigmaPermutation[i];
1062  sortedWeights[i] = w[sigma_i];
1063  sortedParts[i] = oldParts[sigma_i];
1064  }
1065  arrayFloat cumsums;
1066  std::partial_sum(sortedWeights.begin(), sortedWeights.end(), cumsums.begin());
1067 
1068  // resample
1069  // unlike stratified, take advantage of U's being sorted
1070  arrayVec tmpPartics;
1071  unsigned idx;
1072  unsigned int j = 0;
1073  for(size_t i = 0; i < nparts; ++i){ // tmpPartics, Uis
1074 
1075  // find which index
1076  while(j < nparts){
1077 
1078  // get the first time it gets covered by a cumsum
1079  if(cumsums[j] >= ubar_samples[i]){
1080  idx = j;
1081  break;
1082  }
1083 
1084  j++;
1085  }
1086 
1087  // assign
1088  tmpPartics[i] = sortedParts[idx];
1089  }
1090 
1091  //overwrite olds with news
1092  oldParts = std::move(tmpPartics);
1093  std::fill(oldLogUnNormWts.begin(), oldLogUnNormWts.end(), 0.0); // change back
1094 }
1095 
1096 } // namespace resamplers
1097 } //namespace pf
1098 
1099 #endif // RESAMPLERS_H
pf::resamplers::systematic_resampler::arrayInt
std::array< unsigned int, nparts > arrayInt
Definition: resamplers.h:520
pf::resamplers::rbase::arrayVec
std::array< ssv, nparts > arrayVec
Definition: resamplers.h:49
pf::resamplers::stratif_resampler::arrayInt
std::array< unsigned int, nparts > arrayInt
Definition: resamplers.h:415
pf::resamplers::mn_resamp_fast1::mn_resamp_fast1
mn_resamp_fast1()=default
Default constructor.
pf::resamplers::mn_resampler_rbpf::arrayMod
std::array< cfModT, nparts > arrayMod
Definition: resamplers.h:207
pf::resamplers::sys_hilb_resampler
Definition: resamplers.h:1003
pf::resamplers::mn_resampler::arrayInt
std::array< unsigned int, nparts > arrayInt
Definition: resamplers.h:120
pf::resamplers::mn_resamp_fast1::resampLogWts
void resampLogWts(arrayVec &oldParts, arrayFloat &oldLogUnNormWts)
resamples particles.
Definition: resamplers.h:661
pf::resamplers::rbase::m_gen
std::mt19937 m_gen
prng
Definition: resamplers.h:77
pf::resamplers::resid_resampler::resampLogWts
void resampLogWts(arrayVec &oldParts, arrayFloat &oldLogUnNormWts)
resamples particles.
Definition: resamplers.h:340
pf::resamplers::stratif_resampler
Definition: resamplers.h:404
pf::resamplers::sys_hilb_resampler::resampLogWts
void resampLogWts(arrayVec &oldParts, arrayFloat &oldLogUnNormWts, const usvr &ur)
resamples particles.
Definition: resamplers.h:1036
pf::resamplers::rbase_hcs::resampLogWts
virtual void resampLogWts(arrayVec &oldParts, arrayFloat &oldLogUnNormWts, const usvr &ur)=0
Function to resample from log unnormalized weights.
pf::resamplers::resid_resampler::resid_resampler
resid_resampler()=default
Default constructor.
pf::resamplers::rbase::ssv
Eigen::Matrix< float_t, dimx, 1 > ssv
Definition: resamplers.h:47
pf::resamplers::sys_hilb_resampler::sys_hilb_resampler
sys_hilb_resampler()=default
Default constructor. This class does not handle random numbers, so there is no seed-setting.
pf::resamplers::mn_resampler_rbpf::ssv
Eigen::Matrix< float_t, dimsampledx, 1 > ssv
Definition: resamplers.h:201
pf::resamplers::mn_resampler::mn_resampler
mn_resampler()=default
Default constructor.
pf::resamplers::stratif_resampler::resampLogWts
void resampLogWts(arrayVec &oldParts, arrayFloat &oldLogUnNormWts)
resamples particles.
Definition: resamplers.h:449
pf::resamplers::stratif_resampler::stratif_resampler
stratif_resampler()=default
Default constructor.
pf::resamplers::rbase_hcs< nparts, dimx, 1, num_hilb_bits, float_t >::usvr
Eigen::Matrix< float_t, dimur, 1 > usvr
Definition: resamplers.h:899
pf::resamplers::mn_resamp_fast1::arrayInt
std::array< unsigned int, nparts > arrayInt
Definition: resamplers.h:629
pf::resamplers::rbase_hcs< nparts, dimx, 1, num_hilb_bits, float_t >::ssv
Eigen::Matrix< float_t, dimx, 1 > ssv
Definition: resamplers.h:893
pf::resamplers::rbase::arrayFloat
std::array< float_t, nparts > arrayFloat
Definition: resamplers.h:51
pf::resamplers::rbase
Base class for all resampler types.
Definition: resamplers.h:42
pf::resamplers::sys_hilb_resampler::usvr
Eigen::Matrix< float_t, 1, 1 > usvr
Definition: resamplers.h:1016
pf::resamplers::sys_hilb_resampler::arrayVec
std::array< ssv, nparts > arrayVec
Definition: resamplers.h:1010
pf::resamplers::mn_resampler_rbpf::m_gen
std::mt19937 m_gen
prng
Definition: resamplers.h:233
pf::resamplers::sys_hilb_resampler::ssv
Eigen::Matrix< float_t, dimx, 1 > ssv
Definition: resamplers.h:1008
pf::resamplers::mn_resampler_rbpf::arrayVec
std::array< ssv, nparts > arrayVec
Definition: resamplers.h:203
pf::resamplers::rbase_hcs::get_permutation
std::array< unsigned, nparts > get_permutation(const arrayVec &unsortedParts)
get a permutation based on unsorted particle samples (not their weights)
Definition: resamplers.h:967
pf::resamplers::mn_resampler_rbpf::mn_resampler_rbpf
mn_resampler_rbpf()
Default constructor.
Definition: resamplers.h:238
pf::resamplers::sys_hilb_resampler::arrayInt
std::array< unsigned int, nparts > arrayInt
Definition: resamplers.h:1014
pf::resamplers::rbase_hcs::rbase_hcs
rbase_hcs()=default
The default constructor. There is no seed-setting.
pf::resamplers::rbase_hcs
Base class for resampler types that use a Hilbert curve sorting technique.
Definition: resamplers.h:888
pf::resamplers::systematic_resampler
Definition: resamplers.h:509
pf::resamplers::rbase::rbase
rbase()
The default constructor gets called by default, and it sets the seed with the clock.
Definition: resamplers.h:83
pf::resamplers::rbase::resampLogWts
virtual void resampLogWts(arrayVec &oldParts, arrayFloat &oldLogUnNormWts)=0
Function to resample from log unnormalized weights.
pf::resamplers::resid_resampler::arrayInt
std::array< unsigned int, nparts > arrayInt
Definition: resamplers.h:306
pf::resamplers::mn_resamp_fast1
Definition: resamplers.h:618
pf::resamplers::mn_resampler_rbpf
Definition: resamplers.h:196
pf::resamplers::systematic_resampler::systematic_resampler
systematic_resampler()=default
Default constructor.
pf::resamplers::rbase_hcs< nparts, dimx, 1, num_hilb_bits, float_t >::arrayFloat
std::array< float_t, nparts > arrayFloat
Definition: resamplers.h:897
pf::resamplers::mn_resampler_rbpf::arrayFloat
std::array< float_t, nparts > arrayFloat
Definition: resamplers.h:205
pf::resamplers::mn_resampler::resampLogWts
void resampLogWts(arrayVec &oldParts, arrayFloat &oldLogUnNormWts)
resamples particles.
Definition: resamplers.h:153
pf::resamplers::rbase_hcs::hilbertComparison
static bool hilbertComparison(const ssv &first, const ssv &second)
Function that "sorts" multidimensional vectors using an (inverse) Hilbert-curve map....
Definition: resamplers.h:936
pf::resamplers::mn_resampler
Definition: resamplers.h:109
pf::resamplers::systematic_resampler::resampLogWts
void resampLogWts(arrayVec &oldParts, arrayFloat &oldLogUnNormWts)
resamples particles.
Definition: resamplers.h:554
pf::resamplers::mn_resampler_rbpf::resampLogWts
void resampLogWts(arrayMod &oldMods, arrayVec &oldParts, arrayFloat &oldLogUnNormWts)
resamples particles.
Definition: resamplers.h:254
pf::resamplers::resid_resampler
Definition: resamplers.h:295
pf::resamplers::sys_hilb_resampler::arrayFloat
std::array< float_t, nparts > arrayFloat
Definition: resamplers.h:1012
pf::resamplers::rbase_hcs< nparts, dimx, 1, num_hilb_bits, float_t >::arrayVec
std::array< ssv, nparts > arrayVec
Definition: resamplers.h:895