C++ STL random number generation returning the same number

I haven't found similiar question so I apologize if it's already been asked. Anyway, here is my function:

#ifndef OPTIMALIZATION_HPP
#define OPTIMALIZATION_HPP

#include<utility>
#include<random>
#include<experimental/random>
#include<functional>
#include<experimental/functional>
#include<experimental/tuple>
#include<algorithm>
#include<type_traits>
#include<iostream>

namespace numerics{
    template<
        std::size_t population_size, std::size_t generations,
        typename Func,
        typename Compare,
        typename Generator=std::default_random_engine,
        template<typename>
            typename RealDistribution=std::uniform_real_distribution,
        template<typename>
            typename IntegerDistribution=std::uniform_int_distribution,
        typename ...Ts
    >
    auto optimize(
            const Func& function, const Compare& comp,
            const std::pair<Ts,Ts>&... ranges
    ){

        constexpr std::size_t range_argument_count=sizeof...(ranges);
        static_assert(range_argument_count>2,
                "Function needs at least two range arguments"
        );

        //RANDOM NUMBER GENERATORS LAMPDA FUNCTIONS
        auto real_random_generator=[&](const std::pair<auto,auto> range){
            return std::bind(
                    RealDistribution<decltype(range.first)>(range.first,range.second),
                    Generator()
            );
        };

        auto integer_random_generator=[&](const std::pair<auto,auto>& range){
            return std::bind(
                    IntegerDistribution<decltype(range.first)>(range.first,range.second),
                    Generator()
            );
        };

        //MAKING TUPLE OF GENERATORS FOR SPECIFIC RANGES ARGUMENTS
        auto generator_objects=std::make_tuple(
                integer_random_generator,
                real_random_generator
        );
        auto generators=std::make_tuple(
                std::get<std::is_floating_point<decltype(ranges.first)>::value> //UPDATE FOR C++17
                (generator_objects)(ranges)...
        );
        //RANDOMIZES NUMBERS FINE!
        std::cout << std::get<0>(generators)() << std::endl;
        std::cout << std::get<0>(generators)() << std::endl;

        //SINGLE RANDOM INDIVIDUAL GENERATOR
        auto generate_random_individual=[&](const auto& gen){
            auto genotype=std::experimental::apply(
                    [&](auto... x){
                        return std::make_tuple(x()...);
                    },
                    gen
            );
            return std::make_pair(
                    std::experimental::apply(function,genotype),
                    genotype
            );
        };
        //RETURN THE SAME NUMBER!
        auto foo=generate_random_individual(generators);
        auto foo2=generate_random_individual(generators);
        auto foo3=generate_random_individual(generators);
        auto foo4=generate_random_individual(generators);
        std::cout << std::get<0>(foo.second) << std::endl;
        std::cout << std::get<0>(foo2.second) << std::endl;
        std::cout << std::get<0>(foo3.second) << std::endl;
        std::cout << std::get<0>(foo4.second) << std::endl;
        return 1.;
}}
#endif

The most interesting part is where I randomize via function call from one of generators and it works fine (line: //RANDOMIZES NUMBERS FINE!) When I do it in function generate_random_individual (using few generator objects with specific ranges) via the very same function call on the very same object sets (so I'm not making new generators) it returns the same numbers in the last couts.

I can provide test cases if anybody wants it, I wasn't sure if I should include those.

EDIT: I'm leaving this as an example, see my answer if you want to know where exactly the bug was, thanks for help.

Upvotes: 0

Views: 301

Answers (2)

Problem solved - I forgot to add & when passing in one of my functions, namely here:

auto genotype=std::experimental::apply(
                    [&](auto&... x){ //THIS LINE!
                        return std::make_tuple(x()...);
                    },
                    gen
            );

As a result it was copying the generators as most of you said, thanks for input.

Upvotes: 2

andand
andand

Reputation: 17487

You are creating new generators every time you want to use a random number. I don't know how the seed is generated for these generators, but it's clearly using the same seed for each generator instance you create. What you should instead be doing is creating a single generator all of your distributions use.

You might want to look at what the boost random classes offer, and examine some samples there.

Upvotes: 4

Related Questions