c++ - Usando boost:: random como el RNG para std:: random_shuffle
stl boost-random (4)
En C ++ 03, no puede crear una instancia de una plantilla basada en un tipo de función local. Si mueve la clase rand fuera de la función, debería funcionar bien (descargo de responsabilidad: no probado, podría haber otros errores siniestros).
Este requisito se ha relajado en C ++ 0x, pero no sé si el cambio se ha implementado en el modo C ++ 0x de GCC aún, y me sorprendería mucho encontrarlo presente en cualquier otro compilador.
Tengo un programa que usa el generador de números aleatorios mt19937 de boost :: random. Necesito hacer un random_shuffle y quiero que los números aleatorios generados para esto sean de este estado compartido para que puedan ser determinísticos con respecto a los números previamente generados por Twister Twister.
Intenté algo como esto:
void foo(std::vector<unsigned> &vec, boost::mt19937 &state)
{
struct bar {
boost::mt19937 &_state;
unsigned operator()(unsigned i) {
boost::uniform_int<> rng(0, i - 1);
return rng(_state);
}
bar(boost::mt19937 &state) : _state(state) {}
} rand(state);
std::random_shuffle(vec.begin(), vec.end(), rand);
}
Pero recibo un error de plantilla al llamar a random_shuffle con rand. Sin embargo, esto funciona:
unsigned bar(unsigned i)
{
boost::mt19937 no_state;
boost::uniform_int<> rng(0, i - 1);
return rng(no_state);
}
void foo(std::vector<unsigned> &vec, boost::mt19937 &state)
{
std::random_shuffle(vec.begin(), vec.end(), bar);
}
Probablemente porque es una llamada de función real. Pero obviamente esto no mantiene el estado del twister original de mersenne. ¿Lo que da? ¿Hay alguna manera de hacer lo que estoy tratando de hacer sin las variables globales?
En los comentarios, Robert Gould pidió una versión de trabajo para la posteridad:
#include <algorithm>
#include <functional>
#include <vector>
#include <boost/random.hpp>
struct bar : std::unary_function<unsigned, unsigned> {
boost::mt19937 &_state;
unsigned operator()(unsigned i) {
boost::uniform_int<> rng(0, i - 1);
return rng(_state);
}
bar(boost::mt19937 &state) : _state(state) {}
};
void foo(std::vector<unsigned> &vec, boost::mt19937 &state)
{
bar rand(state);
std::random_shuffle(vec.begin(), vec.end(), rand);
}
Estoy usando tr1 en lugar de boost :: random aquí, pero no debería importar mucho.
Lo siguiente es un poco complicado, pero funciona.
#include <algorithm>
#include <tr1/random>
std::tr1::mt19937 engine;
std::tr1::uniform_int<> unigen;
std::tr1::variate_generator<std::tr1::mt19937,
std::tr1::uniform_int<> >gen(engine, unigen);
std::random_shuffle(vec.begin(), vec.end(), gen);
Pensé que valía la pena señalar que esto ahora es bastante sencillo en C ++ 11 usando solo la biblioteca estándar:
#include <random>
#include <algorithm>
std::random_device rd;
std::mt19937 randEng(rd());
std::shuffle(vec.begin(), vec.end(), randEng);