function new_popu = nextpopu(popu, fitness, xover_rate, mut_rate)
new_popu = popu;
popu_s = size(popu, 1);
string_leng = size(popu, 2);
% ====== ELITISM: find the best two and keep them
tmp_fitness = fitness;
[junk, index1] = max(tmp_fitness); % find the best
tmp_fitness(index1) = min(tmp_fitness);
[junk, index2] = max(tmp_fitness); % find the second best
new_popu([1 2], :) = popu([index1 index2], :);
% rescaling the fitness
fitness = fitness - min(fitness); % keep it positive
total = sum(fitness);
if total == 0,
fprintf('=== Warning: converge to a single point ===\n');
fitness = ones(popu_s, 1)/popu_s; % sum is 1
else
fitness = fitness/sum(fitness); % sum is 1
end
cum_prob = cumsum(fitness);
% ====== SELECTION and CROSSOVER
for i = 2:popu_s/2,
% === Select two parents based on their scaled fitness values
tmp = find(cum_prob - rand > 0);
parent1 = popu(tmp(1), :);
tmp = find(cum_prob - rand > 0);
parent2 = popu(tmp(1), :);
% === Do crossover
if rand < xover_rate,
% Perform crossover operation
xover_point = ceil(rand*(string_leng-1));
new_popu(i*2-1, :) = ...
[parent1(1:xover_point) parent2(xover_point+1:string_leng)];
new_popu(i*2, :) = ...
[parent2(1:xover_point) parent1(xover_point+1:string_leng)];
end
% fprintf('xover_point = %d\n', xover_point);
% disp(parent1);
% disp(parent2);
% disp(new_popu(i*2-1, :));
% disp(new_popu(i*2, :));
% keyboard;
end
% ====== MUTATION (elites are not subject to this.)
mask = rand(popu_s, string_leng) < mut_rate;
new_popu = xor(new_popu, mask);
% restore the elites
new_popu([1 2], :) = popu([index1 index2], :);