1

I am using one point cross over to cross two individual. Assume that I have two individual such as

I1='10010011' 
I2='11001101'

tmp_P is vector store two individual I1 and I2. I want to implement one point cross over in C++. Is it right?

This is algorithm description

fori=1 to N/2 (N is number of individual=2 in my case)
   if random[0,1]<=Pc //cross prob.
       pos=random_int[1,n-1]
       for k=pos+1 to n //Length of individual=8 in my case
          aux=tmp_P_i[k]
          tmp_P_i[k]=tmp_P_(i+N/2)[k]
          tmp_P_(i+N/2)[k]=aux;
       end
   end
end

My problem is I am confusing the index of pos. Is it get random from [0 to n-2]. Is it right?

 //Random integer in range [min max]
int random_int(int min, int max) //range : [min, max]
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(min, max);
    return dis(gen);
}
//One-point Crossover
vector< vector<int> > crossover(vector< vector<int> > tmp_P)
{
    int pos=0;
    for (int i=0;i<N/2;i++)
    {
        //If random number smaller than crossover probability then do Crossover
        if(RND()<=Pc)
        {
            pos=random_int(0,n-2);//Index in C++ from 0
            int aux=0;
            for (int k=pos+1;k<n;k++)
            {
                //swat
                aux=tmp_P[i][k];
                tmp_P[i][k]=tmp_P[i+N/2][k];
                tmp_P[i+N/2][k]=aux;
            }
        }
    }
    return tmp_P;
}
Jeff Hammond
  • 5,374
  • 3
  • 28
  • 45
John
  • 2,838
  • 7
  • 36
  • 65
  • Yes, the `std::uniform_int_distribution` will generate numbers uniformly distributed on closed interval `[a,b]`. Therefore, if you want to start your for loop from `pos+1`, you have to use `n-2`. However, I would suggest using `random_int(0,n-1)` and then starting from `k=pos` as it looks cleaner. – Bogdan B May 06 '15 at 08:21

1 Answers1

1
  • random_int

    For debugging purpose (repeatability) you shouldn't always call rd(). Moreover you are recreating the pseudo-RNG at every call.

    Call the random device just once and do everything else with a (randomly) seeded pseudo-RNG. As a bonus, you should store the seed value in a log file so you can later replay the pseudo-random sequence.

    It should be something like:

    int random_int(int min, int max)
    {
    #if defined(NDEBUG)
      static std::mt19937 gen(std::random_device());  // or thread_local  
    #else
      static std::mt19937 gen(1234);  // or, better, thread_local
    #endif
    
      std::uniform_int_distribution<> dis(min, max);
      return dis(gen);
    }
    
  • crossover

    • pos is correct (it's in the [0;n-2] range); the actual crossover position is in the [1;n-1] range (skipping the 0 index is correct since it would swap the entire genome).

      You can directly initialize pos with:

       unsigned pos = random_int(1, n-1);
      
       for (unsigned k = pos; k < n; ++k)
       { /* ... */ }
      

      this is simpler.

    • you could use the std::swap function

    • if variables are habitually assigned a meaningful value when they first appear in the code then there's no chance of them accidentally being used with a meaningless or uninitialised value (e.g. pos / aux, see Why declare a variable in one line, and assign to it in the next?)
    • if the individuals' length is fixed you can also consider std::bitset to store the genome

So something like this should work:

unsigned random_int(unsigned min, unsigned max)
{
#if defined(NDEBUG)
  static std::mt19937 gen(std::random_device());
#else
  static std::mt19937 gen(1234u);
#endif

  std::uniform_int_distribution<> dis(min, max);
  return dis(gen);
}

std::vector<std::vector<int>> crossover(std::vector<std::vector<int>> tmp_P)
{
  const auto N = tmp_P.size();
  const auto n = tmp_P[0].size();

  for (unsigned i = 0; i < N/2; ++i)
  {
    assert(tmp_P[i].size() == n);

    // If random number smaller than crossover probability then do Crossover
    if (RND() <= Pc)
      for (unsigned k = random_int(1, n-1); k < n; ++k)
        std::swap(tmp_P[i][k], tmp_P[i + N/2][k]);
  }

  return tmp_P;
}
Community
  • 1
  • 1
manlio
  • 18,345
  • 14
  • 76
  • 126