Commit c1487e2d authored by maitre's avatar maitre

TGP on GPU working version

parent f4256389
......@@ -733,7 +733,10 @@ if(OPERATING_SYSTEM=WINDOWS)
if( TARGET==CUDA )
strcat(sFileName,"Individual.cu");
else if( TARGET==STD )
strcat(sFileName,"Individual.cpp");
if( TARGET_FLAVOR==CUDA_FLAVOR_GP)
strcat(sFileName,"Individual.cu");
else
strcat(sFileName,"Individual.cpp");
fpOutputFile=fopen(sFileName,"w");
if (bVERBOSE) printf("Creating %s...\n",sFileName);
}
......
50
0.680375,0.133533
-0.211234,0.040727
0.566198,0.147983
0.596880,0.147634
0.823295,0.070360
-0.604897,0.147122
-0.329554,0.086297
0.536459,0.145979
-0.444451,0.127203
0.107940,0.011381
-0.045206,0.002035
0.257742,0.057898
-0.270431,0.062827
0.026802,0.000717
0.904459,0.027083
0.832390,0.065356
0.271423,0.063216
0.434594,0.124264
-0.716795,0.121459
0.213938,0.041676
-0.967399,0.003850
-0.514226,0.143073
-0.725537,0.118069
0.608353,0.146846
-0.686642,0.131701
-0.198111,0.036228
-0.740419,0.111894
-0.782382,0.092093
0.997849,0.000018
-0.563486,0.147894
0.025865,0.000668
0.678224,0.134138
0.225280,0.045730
-0.407937,0.115635
0.275105,0.064660
0.048574,0.002348
-0.012834,0.000165
0.945550,0.010033
-0.414966,0.117999
0.542715,0.146585
0.053490,0.002845
0.539828,0.146317
-0.199543,0.036710
0.783059,0.091750
-0.433371,0.123889
-0.295083,0.072571
0.615449,0.146177
0.838053,0.062231
-0.860489,0.049884
0.898654,0.029901
......@@ -13,7 +13,9 @@ __________________________________________________________*/
#include <cutil.h>
#include <cuda_runtime_api.h>
#define TIMING
#include <timing.h>
#define OPERAND 0
......@@ -24,15 +26,34 @@ __________________________________________________________*/
// Here, some well known parameters for GP.
#define MAX_ARITY 2 // maximum arrity for GP nodes
#define NB_TREES 1 // number of co-evolved trees
#define TREE_DEPTH_MIN 4 // minimum size of (initial) trees (included)
#define TREE_DEPTH_MAX 5 // maximum size of (initial) trees (excluded)
#define TREE_DEPTH_MIN 8 // minimum size of (initial) trees (included)
#define TREE_DEPTH_MAX 9 // maximum size of (initial) trees (excluded)
#define GROW_FULL_RATIO 0.5 // ratio between grow and full construction method
#define DIV_ERR_VALUE 1 // Returned value, in case of non defined input value
#define MAX_XOVER_DEPTH 4
#define MAX_MUTAT_DEPTH 4
#define MAX_XOVER_DEPTH 17
#define MAX_MUTAT_DEPTH 17
// Here, some GPGPGPU parameters
#define MAX_PROGS_SIZE 20000000
float** inputs;
float** outputs;
float* input_k;
float* output_k;
float* progs = NULL;
float* progs_k = NULL;
int* indexes = NULL;
int* indexes_k = NULL;
int* hits = NULL;
int* hits_k = NULL;
float* results = NULL;
float* results_k = NULL;
int fitnessCasesSetLength;
/** For the sake of simplicity, constant operators become first in the function set
......@@ -44,22 +65,34 @@ int fitnessCasesSetLength;
each variable (this sould divide by the number of variables)
*/
#define OP 1
#if 0
enum OPCODE { OP_ERC, OP_W, OP_X, OP_Y, OP_Z, OP_MUL, OP_ADD, OP_SUB, OP_DIV, OP_SIN, OP_COS, OP_EXP, OPCODE_SIZE };
enum OPCODE { OP_ERC, OP_W, OP_X, OP_Y, OP_Z, OP_MUL, OP_ADD, OP_SUB, OP_DIV, OP_SIN, OP_COS, OP_EXP, OPCODE_SIZE, OP_RETURN};
const string opCodeName[]={ "erc" , "w" , "x" , "y" , "z" , "*" , "+" , "-" , "/" , "sin" , "cos" , "exp" };
int opArrity[] = { 0 , 0 , 0 , 0 , 0 , 2 , 2 , 2 , 2 , 1 , 1 , 1 };
int constLen = 5;
int totalLen = OPCODE_SIZE;
#else
enum OPCODE { OP_ERC, OP_W, OP_MUL, OP_ADD, OP_SUB, OP_DIV, OPCODE_SIZE };
const string opCodeName[]={ "erc" , "w" , "*" , "+" , "-" , "/" };
int opArrity[] = { 0 , 0 , 2 , 2 , 2 , 2 };
enum OPCODE { OP_ERC, OP_W, OP_MUL, OP_ADD, OP_SUB, OP_DIV, OPCODE_SIZE, OP_RETURN};
const string opCodeName[]={ "erc" , "w" , "*" , "+" , "-" , "/"};
int opArrity[] = { 0 , 0 , 2 , 2 , 2 , 2 };
int constLen = 2;
int totalLen = OPCODE_SIZE;
#endif
#include "tgp_regressionEval.cu"
\end
\User functions:
#define MILLION_I 1000000
/* Convert a timeval to microseconds as a long */
long misc_tv_usec_l(struct timeval *t){
return ((long) t->tv_sec * MILLION_I) + t->tv_usec;
}
/** This function allows one to load .csv file for 1 input variables.T he file must start with the number
of fitness cases, then it has to contain every inputs values, finally outputs values for each point :
x[0,1], x[0,2], ..., x[0,n], f(x[0])
......@@ -102,6 +135,27 @@ int load_data(float*** inputs, float*** outputs, string filename){
return loaded_size;
}
#define NB_FITNESS_CASES 128
#define POLY(x) x*x*x*x*x*x-2*x*x*x*x+x*x
int generateData(float*** inputs, float*** outputs){
int i=0;
(*inputs) = (float**)malloc(sizeof(**inputs)*NB_FITNESS_CASES);
(*outputs) = (float**)malloc(sizeof(**outputs)*NB_FITNESS_CASES);
for( i=0 ; i<NB_FITNESS_CASES ; i++ ){
(*inputs)[i]=(float*)malloc(sizeof(***inputs));
(*outputs)[i]=(float*)malloc(sizeof(***outputs));
float x = random(-1.0,1.0);
(*inputs)[i][0] = x;
(*outputs)[i][0] = POLY(x);
}
return NB_FITNESS_CASES;
}
void free_data(){
for( int i=0 ; i<fitnessCasesSetLength ;i++ )
......@@ -112,7 +166,7 @@ void free_data(){
free( outputs );
}
/**
/**
Recursive construction method for trees.
Koza construction methods. Function set has to be ordered,
with first every terminal nodes and then non-terminal.
......@@ -128,9 +182,8 @@ void free_data(){
@return : pointer to the root node of the resulting sub tree
*/
GPNode* construction_method( const int constLen, const int totalLen , const int currentDepth,
const int maxDepth, const bool full){
const int maxDepth, const bool full, GPNode* parentPtr){
GPNode* node = new GPNode();
// first select the opCode for the current Node.
if( full ){
if( currentDepth<maxDepth ) node->opCode = random(constLen,totalLen);
......@@ -146,7 +199,7 @@ GPNode* construction_method( const int constLen, const int totalLen , const int
// construct children (if any)
for( int i=0 ; i<arity ; i++ )
node->children[i] = construction_method(constLen, totalLen, currentDepth+1, maxDepth, full );
node->children[i] = construction_method(constLen, totalLen, currentDepth+1, maxDepth, full, node);
// affect null to other array cells (if any)
for( int i=arity ; i<MAX_ARITY ; i++ )
......@@ -173,7 +226,7 @@ void toDotFile_r(GPNode* root, FILE* outputFile){
fprintf(outputFile," %ld [label=\"%s : %f\"];\n", (long int)root, opCodeName[(int)root->opCode].c_str(),
root->erc_value);
else
fprintf(outputFile," %ld [label=\"%s\"];\n", (long int)root, opCodeName[(int)root->opCode].c_str());
fprintf(outputFile," %ld [label=\"%s\"];\n", (long int)root, opCodeName[(int)root->opCode].c_str());
for( int i=0 ; i<root->currentArity ; i++ ){
if( root->children[i] ){
......@@ -196,7 +249,7 @@ void toDotFile(GPNode* root, const char* baseFileName, int treeId){
std::ostringstream oss;
oss << baseFileName << "-" << treeId << ".gv";
FILE* outputFile = fopen(oss.str().c_str(),"a");
FILE* outputFile = fopen(oss.str().c_str(),"w");
if( !outputFile ){
perror("Opening file for outputing dot representation ");
exit(-1);
......@@ -230,10 +283,10 @@ int depthOfTree(GPNode* root){
Recursively evaluate tree for given inputs
*/
double recEvale(GPNode* root, float* inputs){
float recEvale(GPNode* root, float* inputs){
if( root->currentArity==2 ){
double a=recEvale(root->children[0],inputs);
double b=recEvale(root->children[1],inputs);
float a=recEvale(root->children[0],inputs);
float b=recEvale(root->children[1],inputs);
switch( root->opCode ){
case OP_MUL: return a*b;
case OP_ADD: return a+b;
......@@ -242,37 +295,35 @@ double recEvale(GPNode* root, float* inputs){
if( !b ) return DIV_ERR_VALUE;
else return a/b;
default:
fprintf(stderr,"unknown binary opcode %d\n",root->opCode);
fprintf(stderr,"unknown binary opcode %d\n",root->opCode);
exit(-1);
}
}
else if( root->currentArity==1 ){
double a=recEvale(root->children[0],inputs);
float a=recEvale(root->children[0],inputs);
switch( root->opCode ){
#ifdef OP_SIN
case OP_SIN: return sin(a);
#endif
#ifdef OP_COS
case OP_COS: return cos(a);
#endif
#ifdef OP_EXP
case OP_EXP: return exp(a);
#endif
/* case OP_SIN: return sin(a); */
/* case OP_COS: return cos(a); */
/* case OP_EXP: return exp(a); */
default:
fprintf(stderr,"unknown unary opcode %d\n",root->opCode);
fprintf(stderr,"unknown unary opcode %d\n",root->opCode);
exit(-1);
}
}
else
else
switch( root->opCode ){
case OP_ERC: return root->erc_value;
case OP_W: return inputs[0];
#ifdef OP_X
#if OP>1
case OP_X: return inputs[1];
#endif
#ifdef OP_Y
#if OP>2
case OP_Y: return inputs[2];
#ifdefOP_Z
#endif
#if OP>3
case OP_Z: return inputs[3];
#endif
default:
......@@ -286,7 +337,7 @@ double recEvale(GPNode* root, float* inputs){
Fill the collection array with GPNode located at goalDepth
@arg goalDepth: level from which GPNode are collected
@arg collection: an empty, allocated array
@arg collection: an empty, allocated array
*/
int collectNodesDepth(const int goalDepth, GPNode** collection, int collected, int currentDepth, GPNode* root){
......@@ -304,7 +355,7 @@ int collectNodesDepth(const int goalDepth, GPNode** collection, int collected, i
/**
Pick a node in a tree. It first pick a depth and then, it pick a
Pick a node in a tree. It first pick a depth and then, it pick a
node amongst nodes at this depth. It returns the parent node,
and by pointer, the childId of the choosen child.
......@@ -337,7 +388,7 @@ GPNode* selectNode( GPNode* root, int* childId, int* depth){
int reminderP = 0, parentIndexP = 0;
int xoverP = random(0,stockPointCount);
for( int i=0 ; ; )
for( int i=0 ; ; )
if( (i+dNodes[parentIndexP]->currentArity)>xoverP ){
reminderP = xoverP-i;
break;
......@@ -350,43 +401,244 @@ GPNode* selectNode( GPNode* root, int* childId, int* depth){
delete[] dNodes;
return ret;
}
void flattenDatas( float** inputs, int length, int width, float** flat_inputs){
(*flat_inputs)=(float*)malloc(sizeof(float)*length*width);
for( int i=0 ; i<length ; i++ ){
for( int j=0 ; j<width ; j++ ){
(*flat_inputs)[i*width+j] = inputs[i][j];
}
}
}
/**
Send input and output data on the GPU memory.
Allocate
*/
void initialDataToGPU(float* input_f, int length_input, float* output_f, int length_output){
// allocate and copy input/output arrays
CUDA_SAFE_CALL(cudaMalloc((void**)(&input_k),sizeof(float)*length_input));
CUDA_SAFE_CALL(cudaMalloc((void**)(&output_k),sizeof(float)*length_output));
CUDA_SAFE_CALL(cudaMemcpy(input_k,input_f,sizeof(float)*length_input,cudaMemcpyHostToDevice));
CUDA_SAFE_CALL(cudaMemcpy(output_k,output_f,sizeof(float)*length_input,cudaMemcpyHostToDevice));
// allocate indexes and programs arrays
int maxPopSize = MAX(EA->population->parentPopulationSize,EA->population->offspringPopulationSize);
CUDA_SAFE_CALL(cudaMalloc((void**)&indexes_k,sizeof(*indexes_k)*maxPopSize));
CUDA_SAFE_CALL( cudaMalloc((void**)&progs_k,sizeof(*progs_k)*MAX_PROGS_SIZE));
// allocate hits and results arrays
CUDA_SAFE_CALL(cudaMalloc((void**)&results_k,sizeof(*indexes_k)*maxPopSize));
CUDA_SAFE_CALL(cudaMalloc((void**)&hits_k,sizeof(*indexes_k)*maxPopSize));
}
/**
Free gpu memory from the input and ouput arrays.
*/
void free_gpu(){
cudaFree(input_k);
cudaFree(output_k);
cudaFree(progs_k);
cudaFree(indexes_k);
cout << "GPU freed" << endl;
}
int flattening_tree_rpn( GPNode* root, float* buf, int* index){
int i;
for( i=0 ; i<root->currentArity ; i++ ){
flattening_tree_rpn(root->children[i],buf,index);
}
if( (*index)+2>MAX_PROGS_SIZE )return 0;
buf[(*index)++] = root->opCode;
if( root->opCode == OP_ERC ) buf[(*index)++] = root->erc_value;
return 1;
}
int enumTreeNodes(GPNode* root){
int nbNode = 0;
for( int i=0 ; i<root->currentArity ; i++ ){
nbNode+=enumTreeNodes(root->children[i]);
}
return nbNode+1;
}
GPNode* pickNthNode(GPNode* root, int N, int* childId){
GPNode* stack[MAX(MAX(MAX_XOVER_DEPTH,MAX_MUTAT_DEPTH),TREE_DEPTH_MAX)*MAX_ARITY];
GPNode* parentStack[MAX(MAX(MAX_XOVER_DEPTH,MAX_MUTAT_DEPTH),TREE_DEPTH_MAX)*MAX_ARITY];
int stackPointer = 0;
parentStack[stackPointer] = NULL;
stack[stackPointer++] = root;
for( int i=0 ; i<N ; i++ ){
GPNode* currentNode = stack[stackPointer-1];
//cout << currentNode << endl;
stackPointer--;
for( int j=currentNode->currentArity ; j>0 ; j--){
parentStack[stackPointer] = currentNode;
stack[stackPointer++] = currentNode->children[j-1];
}
}
//assert(stackPointer>0);
if( stackPointer )
stackPointer--;
//cout << "f : \n\t n :" << stack[stackPointer ] << "\n\t p :" << parentStack[stackPointer] << " cId : " << (*childId) << endl;
for( int i=0 ; i<parentStack[stackPointer]->currentArity ; i++ ){
if( parentStack[stackPointer]->children[i]==stack[stackPointer] ){
(*childId)=i;
break;
}
}
return parentStack[stackPointer];
}
int depthOfNode(GPNode* root, GPNode* node){
if( root==node ){
return 1;
}
else{
for( int i=0 ; i<root->currentArity ; i++ ){
int depth = depthOfNode(root->children[i],node);
if( depth )
return depth+1;
}
return 0;
}
}
void simpleCrossOver(IndividualImpl& p1, IndividualImpl& p2, IndividualImpl& c){
int depthP1 = depthOfTree(p1.root[0]);
int depthP2 = depthOfTree(p2.root[0]);
int nbNodeP1 = enumTreeNodes(p1.root[0]);
int nbNodeP2 = enumTreeNodes(p2.root[0]);
int stockPointChildId=0;
int graftPointChildId=0;
bool stockCouldBeTerminal = tossCoin(0.9);
bool graftCouldBeTerminal = tossCoin(0.9);
int childrenDepth, Np1, Np2;
GPNode* stockParentNode ;
GPNode* graftParentNode ;
do{
if( stockCouldBeTerminal ) Np1 = random(0,nbNodeP1);
else Np1 = random(0,nbNodeP1-1);
if( graftCouldBeTerminal ) Np2 = random(0,nbNodeP2);
else Np2 = random(0,nbNodeP2-1);
if( Np1 ) stockParentNode = pickNthNode(c.root[0], MIN(Np1,nbNodeP1) ,&stockPointChildId);
if( Np2 ) graftParentNode = pickNthNode(p2.root[0], MIN(Np2,nbNodeP1) ,&graftPointChildId);
if( Np2 && Np1)
childrenDepth = depthOfNode(c.root[0],stockParentNode)+depthOfTree(graftParentNode->children[graftPointChildId]);
else if( Np1 ) childrenDepth = depthOfNode(c.root[0],stockParentNode)+depthP1;
else if( Np2 ) childrenDepth = depthOfTree(graftParentNode->children[graftPointChildId]);
else childrenDepth = depthP2;
}while( childrenDepth>MAX_XOVER_DEPTH );
if( Np1 && Np2 ){
delete stockParentNode->children[stockPointChildId];
stockParentNode->children[stockPointChildId] = graftParentNode->children[graftPointChildId];
graftParentNode->children[graftPointChildId] = NULL;
}
else if( Np1 ){ // && Np2==NULL
// We want to use the root of the parent 2 as graft
delete stockParentNode->children[stockPointChildId];
stockParentNode->children[stockPointChildId] = p2.root[0];
p2.root[0] = NULL;
}else if( Np2 ){ // && Np1==NULL
// We want to use the root of the parent 1 as stock
delete c.root[0];
c.root[0] = graftParentNode->children[graftPointChildId];
graftParentNode->children[graftPointChildId] = NULL;
}else{
// We want to switch root nodes between parents
delete c.root[0];
c.root[0] = p2.root[0];
p2.root[0] = NULL;
}
toDotFile(c.root[0],"out/xover/cf",0);
}
\end
\Before everything else function:
{
int maxPopSize = MAX(EA->population->parentPopulationSize,EA->population->offspringPopulationSize);
// load data from csv file.
cout<<"Before everything else function called "<<endl;
fitnessCasesSetLength = load_data(&inputs,&outputs,"quadra_reg_data.csv");
//fitnessCasesSetLength = load_data(&inputs,&outputs,"data_koza_sextic.csv");
fitnessCasesSetLength = generateData(&inputs,&outputs);
cout << "number of point in fitness cases set : " << fitnessCasesSetLength << endl;
float* inputs_f = NULL;
float* outputs_f = NULL;
flattenDatas(inputs,fitnessCasesSetLength,VAR_LEN,&inputs_f);
flattenDatas(outputs,fitnessCasesSetLength,NB_TREES,&outputs_f);
indexes = new int[maxPopSize];
hits = new int[maxPopSize];
results = new float[maxPopSize];
progs = new float[MAX_PROGS_SIZE];
INSTEAD_EVAL_STEP=true;
// Adding another stopping, as we are minimizing, the goal is 0
CGoalCriterion* gc = new CGoalCriterion(0,true);
EA->stoppingCriteria.push_back(gc);
//INSTEAD_EVAL_STEP=false;
// Adding another stopping, as we are minimizing, the goal is 0
//CGoalCriterion* gc = new CGoalCriterion(0,true);
//EA->stoppingCriteria.push_back(gc);
// Here starts the CUDA parts
cudaSetDevice(1); // on GTX295 ;) we want to use the second card for computation
initialDataToGPU(inputs_f, fitnessCasesSetLength*VAR_LEN, outputs_f, fitnessCasesSetLength*NB_TREES);
cout << "seed is : " << EA->params->seed << endl;
}
\end
\After everything else function:
{
// write both trees of every individuals in a separate file.
// write tree of every individuals in a separate file.
for( unsigned int i=0 ; i<population->actualParentPopulationSize ; i++ ){
std::ostringstream oss;
oss << "out/indiv-" << i << "-trees" ;
toDotFile( ((IndividualImpl*)population->parents[i])->root[0],oss.str().c_str(),0);
}
// not sure that the population is not sorted now. So lets do another time (or check in the code;))
// not sure that the population is sorted now. So lets do another time (or check in the code;))
// and dump the best individual in a graphviz file.
population->sortParentPopulation();
toDotFile( ((IndividualImpl*)population->parents[0])->root[0], "best-of-run",0);
// delete some global arrays
delete[] indexes; delete[] hits;
delete[] results; delete[] progs;
free_gpu();
free_data();
}
\end
......@@ -405,9 +657,60 @@ GPNode* selectNode( GPNode* root, int* childId, int* depth){
\Instead evaluation function:
{
DECLARE_TIME(gpu_eval);
TIME_ST(gpu_eval);
int index = 0;
for( int i=0 ; i<popSize ; i++ ){
indexes[i] = index;
flattening_tree_rpn( ((IndividualImpl*)population[i])->root[0], progs, &index);
progs[index++] = OP_RETURN;
}
CUDA_SAFE_CALL(cudaMemcpy( progs_k, progs, sizeof(float)*index, cudaMemcpyHostToDevice ));
CUDA_SAFE_CALL(cudaMemcpy( indexes_k, indexes, sizeof(float)*popSize, cudaMemcpyHostToDevice ));
// Here we will do the real GPU evaluation
EvaluatePostFixIndividuals_128<<<popSize,128>>>( progs_k, index, popSize, input_k, output_k, fitnessCasesSetLength, results_k, hits_k, indexes_k);
TIME_END(gpu_eval);
CUDA_SAFE_CALL(cudaMemcpy( hits, hits_k, sizeof(float)*popSize, cudaMemcpyDeviceToHost));
CUDA_SAFE_CALL(cudaMemcpy( results, results_k, sizeof(float)*popSize, cudaMemcpyDeviceToHost));
for( int i=0 ; i<popSize ; i++ ){
cout << population[i] << endl;
//population[i]->fitness = results[i];
//population[i]->valid = true;
}
int err=0;
DECLARE_TIME(cpu_eval);
TIME_ST(cpu_eval);
for( int i=0 ; i<popSize ; i++ ){
population[i]->evaluate();
population[i]->valid = true;
if( fabs(results[i]-population[i]->getFitness())>population[i]->getFitness()*0.05){
err++;
/* toDotFile(((IndividualImpl*)population[i])->root[0],"error",0); */
/* int k = indexes[i]; */
/* while( progs[k]!=OP_RETURN ){ */
/* cout << progs[k++] << ", " ; */
/* } */
/* cout << endl; */
/* exit(-1); */
//printf("err %d = %f | %f\n",i,results[i],population[i]->getFitness());
}
}
TIME_END(cpu_eval);
//SHOW_TIME(cpu_eval);
SHOW_TIME_FLAT(cpu_eval);
cout << "," ;
SHOW_TIME_FLAT(gpu_eval);
double speedUp = misc_tv_usec_l(&cpu_eval_res)/misc_tv_usec_l(&gpu_eval_res);
cout << "," << speedUp<< endl;
cout << "Error : " << err << "/" << popSize << endl;
}
\end
......@@ -419,7 +722,7 @@ GPNode {
double erc_value;
}
GenomeClass {
GenomeClass {
GPNode* root[NB_TREES];
}
\end
......@@ -448,146 +751,15 @@ GenomeClass {
//cout << seg << " " << currentDepth << " " << full ;
for( int i=0 ; i<NB_TREES ; i++ ){
Genome.root[i] = construction_method( constLen, totalLen , 1, currentDepth ,full);
Genome.root[i] = construction_method( constLen, totalLen , 1, currentDepth ,full, Genome.root[i] );
}
}
\end
\GenomeClass::crossover :
{
/**
Crossover for GP trees.
It selects depths of cross, then selects which nodes
will be exchanged at those depths.
*/
for( int tree=0 ; tree<NB_TREES ; tree++ ){
int depthOfStock, depthOfGraft;
GPNode** d1Nodes = NULL, ** d2Nodes = NULL;
int reminderP1, reminderP2;
int parentIndexP1, parentIndexP2;
bool graftIsRoot = false;
bool stockIsRoot = false;
do{
int depthP1 = depthOfTree(parent1.root[tree]);
int depthP2 = depthOfTree(parent2.root[tree]);
int xoverD1 = random(0,depthP1);
int xoverD2 = random(0,depthP2);
int maxNode1 = 1<<(depthP1-1);
int maxNode2 = 1<<(depthP2-1);
if( d1Nodes ) delete[] d1Nodes;