#ifndef CUMULATIVESAMPLER_H #define CUMULATIVESAMPLER_H #include #include #include #include "../Particle.h" #include "ParticleTrajectorieSampler.h" namespace SMC { /** * drawing trajectories using a cumulative drawer */ template class CumulativeSampler : public ParticleTrajectorieSampler { public: /** ctor */ CumulativeSampler(){ } /** draw a single particle */ Particle drawSingleParticle(std::vector> const& particles){ // ensure the copy vector has the same size as the real particle vector std::vector> particlesCopy; particlesCopy.resize(particles.size()); // swap both vectors particlesCopy = particles; // calculate cumulative weight double cumWeight = 0; for (uint32_t i = 0; i < particles.size(); ++i) { cumWeight += particlesCopy[i].weight; particlesCopy[i].weight = cumWeight; } return draw(cumWeight, particlesCopy, particles); } /** draw a trajectorie of n particles */ std::vector> drawTrajectorie(std::vector> const& particles, const int numRealizations){ // ensure the copy vector has the same size as the real particle vector std::vector> particlesCopy; particlesCopy.reserve(particles.size()); particlesCopy = particles; // calculate cumulative weight double cumWeight = 0; for (uint32_t i = 0; i < particles.size(); ++i) { cumWeight += particlesCopy[i].weight; particlesCopy[i].weight = cumWeight; } // now draw the initial weights and therefore the corresponding particles std::vector> trajectorie; trajectorie.reserve(numRealizations); for (uint32_t i = 0; i < numRealizations; ++i) { trajectorie.push_back(draw(cumWeight, particlesCopy, particles)); } return trajectorie; } private: /** function for drawing particles */ Particle draw(const double cumWeight, std::vector> const& cumParticles, std::vector> const& origParticles){ // random value between [0;1] const double rand01 = double(rand()) / double(RAND_MAX); // random value between [0; cumulativeWeight] const double rand = rand01 * cumWeight; // search comparator auto comp = [] (const Particle& s, const double d) {return s.weight < d;}; auto it = std::lower_bound(cumParticles.begin(), cumParticles.end(), rand, comp); //get the idx for the iterator it. this is the same as std::distance(..,..) int idx = it - cumParticles.begin(); //get the original weight instead of the cumulative weight Particle drawnParticle = *it; drawnParticle.weight = origParticles[idx].weight; return drawnParticle; } }; } #endif // ARTIFICIALDISTRIBUTION_H