📄 reproduce.m
字号:
new_individual=population(NewChrIx(number_crossover+count_individuals_species));
end
% Hidden nodes culling (remove any hidden nodes where there is no corresponding connection gene in the new individual)
connected_nodes=[];
for index_node_culling=1:size(new_individual.nodegenes,2)
node_connected_flag=sum(new_individual.connectiongenes(2,:)==new_individual.nodegenes(1,index_node_culling))+sum(new_individual.connectiongenes(3,:)==new_individual.nodegenes(1,index_node_culling));
if (node_connected_flag>0) | (new_individual.nodegenes(2,index_node_culling)~=3);
connected_nodes=[connected_nodes,new_individual.nodegenes(:,index_node_culling)];
end
end
new_individual.nodegenes=connected_nodes;
% Disabled Genes Mutation
%run through all connection genes in a new_individual, find disabled connection genes, enable again with crossover.probability_gene_reenabled probability
for index_connection_gene=1:size(new_individual.connectiongenes,2)
if (new_individual.connectiongenes(5,index_connection_gene)==0)& (rand<mutation.probability_gene_reenabled)
new_individual.connectiongenes(5,index_connection_gene)=1;
end
end
% Weight Mutation
%run through all connection genes in a new_individual, decide on mutating or not
for index_connection_gene=1:size(new_individual.connectiongenes,2)
if rand<mutation.probability_mutate_weight %*index_connection_gene/size(new_individual.connectiongenes,2) %linearly biased towards higher probability of mutation at end of connection genes
new_individual.connectiongenes(4,index_connection_gene)=new_individual.connectiongenes(4,index_connection_gene)+mutation.weight_range*(rand-0.5);
end
% weight capping
new_individual.connectiongenes(4,index_connection_gene)=new_individual.connectiongenes(4,index_connection_gene)*(abs(new_individual.connectiongenes(4,index_connection_gene))<=mutation.weight_cap)+(sign(new_individual.connectiongenes(4,index_connection_gene))*mutation.weight_cap)*(abs(new_individual.connectiongenes(4,index_connection_gene))>mutation.weight_cap);
end
% IMPORTANT: The checks for duplicate innovations in the following two types of mutation can only check in the current generation
% Add Connection Mutation
flag_recurrency_enabled=rand<mutation.probability_recurrency;
vector_possible_connect_from_nodes=new_individual.nodegenes(1,:); %connections can run from every node
vector_possible_connect_to_nodes=new_individual.nodegenes(1,find((new_individual.nodegenes(2,:)==2)+(new_individual.nodegenes(2,:)==3))); %connections can only run into hidden and output nodes
number_possible_connection=length(vector_possible_connect_from_nodes)*length(vector_possible_connect_to_nodes)-size(new_individual.connectiongenes,2);
flag1=(rand<mutation.probability_add_node);
if (rand<mutation.probability_add_connection) & (number_possible_connection>0) & (flag1==0) %check if new connections can be added to genes (if there are any possible connections which are not already existing in genes of new individual)
% First build matrix containing all possible new connection for nodegene of new individual
new_connection_matrix=[];
for index_connect_from=1:length(vector_possible_connect_from_nodes)
for index_connect_to=1:length(vector_possible_connect_to_nodes)
possible_connection=[vector_possible_connect_from_nodes(index_connect_from);vector_possible_connect_to_nodes(index_connect_to)];
if sum((new_individual.connectiongenes(2,:)==possible_connection(1)).*(new_individual.connectiongenes(3,:)==possible_connection(2)))==0 % Check if proposed connection is not already contained in gene
new_connection_matrix=[new_connection_matrix,possible_connection];
end
end
end
% Shuffle possible new connections randomly
[discard,shuffle]=sort(rand(1,size(new_connection_matrix,2)));
new_connection_matrix=new_connection_matrix(:,shuffle);
index_new_connection=0;
flag_connection_ok=0;
% check if connection is o.k. (meaning either non-recurrent or recurrent and flag_recurrency_enabled set to 1) if not connection is found which is o.k.,no connection will be added to connection genes of new individual
while (flag_connection_ok==0) & (index_new_connection<size(new_connection_matrix,2))
index_new_connection=index_new_connection+1;
new_connection=new_connection_matrix(:,index_new_connection);
% test new connection if it is recurrent (i.e. at least one of the possibles path starting from connect_to node in the network leads back to the connect_from node
flag_recurrent=0;
if new_connection(1)==new_connection(2) %trivial recurrency
flag_recurrent=1;
end
nodes_current_level=new_connection(2);
depth=0;
while flag_recurrent==0 & depth<size(new_individual.connectiongenes,2) & ~isempty(nodes_current_level)
depth=depth+1;
nodes_next_level=[];
for index_check=1:size(nodes_current_level);
nodes_next_level=[nodes_next_level,new_individual.connectiongenes(3,find(new_individual.connectiongenes(2,:)==nodes_current_level(index_check)))];
end
if sum(nodes_next_level(:)==new_connection(1))>0
flag_recurrent=1;
end
nodes_current_level=nodes_next_level;
end
if flag_recurrent==0
flag_connection_ok=1;
elseif flag_recurrency_enabled
flag_connection_ok=1;
end
end
% Now we test if it is a true innovation (i.e. hasn't already happened in this generation) we can only do this if a valid new connection has been found
if flag_connection_ok
index_already_happened=find((innovation_record(5,:)==generation).*(innovation_record(2,:)==new_connection(1)).*(innovation_record(3,:)==new_connection(2))); %set flag signifying new innovation (connection not contained in innovation_record of this generation)
new_innovation=not(sum(index_already_happened));
if new_innovation==1 % O.K. is new innovation
new_connection=[max(innovation_record(1,:))+1;new_connection]; %Update the new connection with its innovation number
% Update connection_genes
new_individual.connectiongenes=[new_individual.connectiongenes,[new_connection;rand*2-1;1]];
% Update innovation_record
innovation_record=[innovation_record,[new_connection;0;generation]];
else % connection gene already exists in innovation_record of this generation
% Update connection_genes
new_individual.connectiongenes=[new_individual.connectiongenes,[innovation_record(1:3,index_already_happened);rand*2-1;1]];
end
end
end
% Add (Insert) Node Mutation
new_innovation=0;
if flag1==1
max_old_innovation_number=max((innovation_record(5,:)<generation).*innovation_record(1,:)); %highest innovation number from last generation (to ensure that only connections from from last generation or older are chosen for add node mutation, otherwise a new connection added in the last mutation might instantly be disabled)
vector_possible_connections=[new_individual.connectiongenes(2:3,find((new_individual.connectiongenes(5,:)==1) & (new_individual.connectiongenes(1,:)<=max_old_innovation_number)));find((new_individual.connectiongenes(5,:)==1) & (new_individual.connectiongenes(1,:)<=max_old_innovation_number))]; %compute vector of connections into which a new node could be inserted and their positions in the connection_gene matrix. This vector is composed of all nondisabled connections which stem at least from the last generation or older
insert_node_connection=vector_possible_connections(:,round(rand*size(vector_possible_connections,2)+0.5));
new_innovation=1; %set provisionally to 1, will be checked
exist_innovation=find((innovation_record(5,:)==generation).*(innovation_record(4,:)>0).*(innovation_record(2,:)==insert_node_connection(1))); %Beginning of check innovation record to test for real innovation. exist_innovation contains vector of index of elements in innovation record which fulfil three things: current generation, add node mutation and same connect from as current innovation
if sum(exist_innovation)>0 %if these are fulfilled, we have to test for connect_to node to see if innovation really is the same
for index_check=1:length(exist_innovation)
if innovation_record(3,exist_innovation(index_check)+1)==insert_node_connection(2)
new_innovation=0;
index_already_existent_this_generation=exist_innovation(index_check);
end
end
end
if new_innovation==1 %O.K. is true innovation for current generation
% Update node_genes
new_node_number=max(innovation_record(4,:))+1;
new_individual.nodegenes=[new_individual.nodegenes,[new_node_number;3;0;0]];
% Update connection_genes
new_individual.connectiongenes(5,insert_node_connection(3))=0; %disable old connection gene
new_connections=[[max(innovation_record(1,:))+1;insert_node_connection(1);new_node_number;1;1],[max(innovation_record(1,:))+2;new_node_number;insert_node_connection(2);new_individual.connectiongenes(4,insert_node_connection(3));1]];
new_individual.connectiongenes=[new_individual.connectiongenes,new_connections]; %extend connection_genes by the two new connections
% Update innovation_record
innovation_record=[innovation_record,[new_connections(1:3,:);new_node_number,0;generation,generation]];
else %no new innovation, has already happened at least once in this generation
% Update node_genes
node_number=innovation_record(4,index_already_existent_this_generation);
new_individual.nodegenes=[new_individual.nodegenes,[node_number;3;0;0]];
% Update connection_genes
new_individual.connectiongenes(5,insert_node_connection(3))=0; %disable old connection gene
new_connections=[innovation_record(1:3,index_already_existent_this_generation:index_already_existent_this_generation+1);1,new_individual.connectiongenes(4,insert_node_connection(3));1,1];
length_con_gen=size(new_individual.connectiongenes,2); %length of the connection genes of current new_individual
if new_individual.connectiongenes(1,length_con_gen)>new_connections(1,2) % check if there was an add_connection_mutation to current new_individual which has a higher innovation number than current add_node_mutation
new_individual.connectiongenes=[new_individual.connectiongenes(:,1:length_con_gen-1),new_connections,new_individual.connectiongenes(:,length_con_gen)];
else
new_individual.connectiongenes=[new_individual.connectiongenes,new_connections];
end
end
end
%% Speciation
% Loop through comparison vector
species_assigned=0;
index_population_ref=0;
while species_assigned==0 & index_population_ref<size(population_ref,2)
%extract reference_individual from reference population
index_population_ref=index_population_ref+1;
reference_individual=population_ref(index_population_ref);
%run through both connection genes, compute disjoint, excess, and average weight difference
max_num_genes=max([size(new_individual.connectiongenes,2),size(reference_individual.connectiongenes,2)]);
max_num_innovation=max([new_individual.connectiongenes(1,:),reference_individual.connectiongenes(1,:)]);
vector_innovation_new=[zeros(1,max(new_individual.connectiongenes(1,:))),ones(1,max_num_innovation-max(new_individual.connectiongenes(1,:)))];
vector_innovation_new(new_individual.connectiongenes(1,:))=2;
vector_weight_new=zeros(1,max_num_innovation);
vector_weight_new(new_individual.connectiongenes(1,:))=new_individual.connectiongenes(4,:);
vector_innovation_ref=[4*ones(1,max(reference_individual.connectiongenes(1,:))),8*ones(1,max_num_innovation-max(reference_individual.connectiongenes(1,:)))];
vector_innovation_ref(reference_individual.connectiongenes(1,:))=16;
vector_weight_ref=zeros(1,max_num_innovation);
vector_weight_ref(reference_individual.connectiongenes(1,:))=reference_individual.connectiongenes(4,:);
vector_lineup=vector_innovation_new+vector_innovation_ref;
excess=sum(vector_lineup==10)+sum(vector_lineup==17);
disjoint=sum(vector_lineup==6)+sum(vector_lineup==16);
vector_matching=find(vector_lineup==18);
average_weight_difference=sum(abs(vector_weight_new(vector_matching)-vector_weight_ref(vector_matching)))/length(vector_matching);
max_num_genes=1;
distance=speciation.c1*excess/max_num_genes+speciation.c2*disjoint/max_num_genes+speciation.c3*average_weight_difference;
if distance<speciation.threshold
% assign individual to same species as current reference individual
new_individual.species=reference_individual.species;
species_assigned=1; %set flag indicating new_individual has been assigned to species
end
end
% not compatible with any? well, then create new species
if species_assigned==0
new_species_ID=size(species_record,2)+1;
% assign individual to new species
new_individual.species=new_species_ID;
% update species_record
species_record(new_species_ID).ID=new_species_ID;
species_record(new_species_ID).number_individuals=1;
species_record(new_species_ID).generation_record=[];
% update population reference
population_ref(size(population_ref,2)+1)=new_individual;
end
% add new_individual to new_population
new_population(index_individual)=new_individual;
%Increment species
matrix_existing_and_propagating_species(3,index_species)=matrix_existing_and_propagating_species(3,index_species)+1;
end
end
% final update of species_record (can only be done now since old population sizes were needed during reproduction cycle)
for index_species=1:size(species_record,2)
species_record(index_species).number_individuals=sum([new_population(:).species]==index_species);
end
%assign updated species_record to output
updated_species_record=species_record;
%assign updated innovation_record to output
updated_innovation_record=innovation_record;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -