/*======================================================================== PISA (www.tik.ee.ethz.ch/pisa/) ======================================================================== Computer Engineering (TIK) ETH Zurich ======================================================================== SPAM - Set Preference Algorithm for Multiobjective Optimization authors: Johannes Bader, johannes.bader@tik.ee.ethz.ch Eckart Zitzler, eckart.zitzler@tik.ee.ethz.ch Marco Laumanns, laumanns@tik.ee.ethz.ch revision by: Stefan Bleuler, stefan.bleuler@tik.ee.ethz.ch Dimo Brockhoff, dimo.brockhoff@tik.ee.ethz.ch last change: 01.12.2008 ======================================================================== */ #include #include #include #include #include #include "population.h" #include "dominance.h" #include "utils.h" /* "glue.h": When using prefrel for statistical testing * "reduction.h": When using prefrel as part of the PISA environment */ //#include "glue.h" #include "reduction.h" int alpha, lambda, mu, dim; /* population containers */ pop *pp_all = NULL; // Archive pop *pp_new = NULL; // Offspring / Exchange pop *pp_sel = NULL; // Parent void resetPPAll() { pp_all->size = 0; } void setPopSizes( int a, int l, int m, int d ) { alpha = a; lambda = l; mu = m; dim = d; } void insertInPart(fpart* partp, int frontNo, int indIndex, int performSorting, int ranking ) { int i, j, k; int* mem; int proceedNextFront, dominators; proceedNextFront = 1; dominators = 0; i = frontNo; if (performSorting == 1) { while (i < partp->fronts && proceedNextFront) { proceedNextFront = 0; if (ranking == 0) k = i; else k = partp->fronts - 1 - (i - frontNo); mem = partp->front_array[k].members; j = 0; while (!proceedNextFront && j < partp->front_array[k].size) switch (dominanceCheckInd(mem[j], indIndex)) { case a_better_b: if (ranking == 0) proceedNextFront = 1; else { j++; dominators++; } break; case b_better_a: if ( ranking == 0) { int temp = mem[j]; partp->size--; partp->front_array[k].size--; mem[j] = mem[partp->front_array[k].size]; insertInPart(partp, k + 1, temp, performSorting, ranking); } else { if (k + 1 >= partp->fronts) { partp->front_array[k + 1].size = 0; partp->fronts++; } partp->front_array[k + 1].members[partp->front_array[k + 1].size] = mem[j]; partp->front_array[k + 1].size++; partp->front_array[k].size--; mem[j] = mem[partp->front_array[k].size]; } break; default: j++; break; } if (ranking != 0) proceedNextFront = 1; if (proceedNextFront) i++; } if (ranking != 0) i = dominators; } assert(i < partp->max_fronts && partp->front_array[i].size <= partp->max_fronts); if (i >= partp->fronts) { partp->fronts = i + 1; partp->front_array[i].size = 0; } partp->front_array[i].members[partp->front_array[i].size] = indIndex; partp->front_array[i].size++; partp->size++; } void performDominanceSorting(int ranking, fpart* partp) { int i, j; int size; int* popArray; popArray = chk_malloc(sizeof(int) * (alpha + lambda)); size = 0; for (i = 0; i < partp->fronts; i++) for (j = 0; j < partp->front_array[i].size; j++) popArray[size++] = partp->front_array[i].members[j]; cleanPart(partp); while (size > 0) insertInPart(partp, 0, popArray[--size], 1, ranking); chk_free(popArray); popArray = NULL; } void setFitness(int index, double value ) { assert( index >= 0 && index < pp_all->size ); pp_all->ind_array[index]->fitness = value; } double getFitness(int index) { assert( index >= 0 && index < pp_all->size ); return pp_all->ind_array[index]->fitness; } void increaseFitness(int index, double value ) { pp_all->ind_array[index]->fitness += value; } void undoDominanceSorting(fpart* partp, int ranking ) { int i, j; int size; int* popArray; popArray = chk_malloc(sizeof(int) * (alpha + lambda)); size = 0; for (i = 0; i < partp->fronts; i++) for (j = 0; j < partp->front_array[i].size; j++) popArray[size++] = partp->front_array[i].members[j]; cleanPart(partp); while (size > 0) insertInPart(partp, 0, popArray[--size], 0, ranking ); chk_free(popArray); popArray = NULL; } void cleanPart(fpart* partp) { int i; for (i = 0; i < partp->max_fronts; i++) partp->front_array[i].size = 0; partp->size = 0; partp->fronts = 0; } void copyPart(fpart* sourcep, fpart* destp) { int i; assert(sourcep->max_fronts <= destp->max_fronts); if (sourcep != destp) { cleanPart(destp); for (i = 0; i < sourcep->fronts; i++) { memcpy(destp->front_array[i].members, sourcep->front_array[i].members, sourcep->max_fronts * sizeof(int)); destp->front_array[i].size = sourcep->front_array[i].size; } destp->fronts = sourcep->fronts; destp->size = sourcep->size; } } void updateBounds(int scaling) { int i,k; double temp; /* get points and compute bounds for each dimension, if( scaling == 2 ) * don't let the lowerbounds increase */ for (k = 0; k < dim; k++) { if( scaling != 2 ) pp_all->lowerbounds[k] = DBL_MAX; // ensuring correct minimum pp_all->upperbounds[k] = -DBL_MAX; // ensuring correct maximum } for (i = 0; i < pp_all->size; i++) { for (k = 0; k < dim; k++) { temp = pp_all->ind_array[i]->f_u[k]; //assert(temp >= 0); if (temp < pp_all->lowerbounds[k]) pp_all->lowerbounds[k] = temp; if (temp > pp_all->upperbounds[k]) pp_all->upperbounds[k] = temp; } } } void scaleObjectiveValues( int scaling ) /* Scales the (unscaled) objective values f_u and stores the result in f_s * (if no scaling is chosen, nothing is done. The scaled values remain copies * of the unscaled vectors in this case) */ { int k, j; if( scaling == 0 ) return; for( k = 0; k < pp_all->dim; k++ ) { assert( pp_all->upperbounds[k] >= pp_all->lowerbounds[k] ); for( j = 0; j < pp_all->size; j++ ) { if( pp_all->upperbounds[k] > pp_all->lowerbounds[k] ) pp_all->ind_array[j]->f_s[k] = ( pp_all->ind_array[j]->f_u[k] - pp_all->lowerbounds[k] ) / ( pp_all->upperbounds[k] - pp_all->lowerbounds[k] ); else { pp_all->ind_array[j]->f_s[k] = 1; } } } } void setObjectiveVector( int index, double* objectiveValues, int dim ) { int o; if( pp_all == NULL ) { fprintf(stderr, "Population pp_all not created, cannot assign objective vector\n"); exit(1); } assert( pp_all != NULL ); assert( index >= 0 ); assert( dim == pp_all->dim ); assert( index < pp_all->size ); for( o = 0; o < dim; o++ ) { pp_all->ind_array[index]->f_u[o] = objectiveValues[o]; pp_all->ind_array[index]->f_s[o] = objectiveValues[o]; } } void doScaling(int scaling) { if( scaling > 0 ) { updateBounds(scaling); scaleObjectiveValues(scaling); } } void free_pop(pop *pp) /* Frees memory for given population. */ { if (pp != NULL) { chk_free(pp->ind_array); chk_free(pp->obj); chk_free(pp->lowerbounds); chk_free(pp->upperbounds); chk_free(pp); } pp = NULL; } void cleanUpArchive(fpart* partp) /* removes all individuals from pp_all that are not referenced in partp */ { pop* new_pop; int i, j; new_pop = create_pop(alpha + lambda, dim); new_pop->size = 0; for (i = partp->fronts - 1; i >= 0; i--) { for (j = partp->front_array[i].size - 1; j >= 0; j--) { int index = partp->front_array[i].members[j]; new_pop->ind_array[new_pop->size] = pp_all->ind_array[index]; pp_all->ind_array[index] = NULL; partp->front_array[i].members[j] = new_pop->size; new_pop->size++; } } new_pop->obj = pp_all->obj; pp_all->obj = NULL; new_pop->lowerbounds = pp_all->lowerbounds; pp_all->lowerbounds = NULL; new_pop->upperbounds = pp_all->upperbounds; pp_all->upperbounds = NULL; complete_free_pop(pp_all); pp_all = new_pop; } void determineIndexAndFront(fpart* partp, int n, int* index, int* front, int sorting) { int i; if (sorting != 0) { i = partp->fronts - 1; while (i >= 0 && (n - partp->front_array[i].size) >= 0) { n -= partp->front_array[i].size; i--; } assert(i >= 0 && n >= 0 && n < partp->front_array[i].size); *index = partp->front_array[i].members[n]; *front = i; } else { *index = n; *front = 0; } } void free_front_part(fpart* partp) { int i; if (partp->front_array != NULL) { for (i = 0; i < partp->max_fronts; i++) if (partp->front_array[i].members != NULL) chk_free(partp->front_array[i].members); chk_free(partp->front_array); partp->front_array = NULL; } partp->fronts = 0; partp->max_fronts = 0; partp->size = 0; } void free_ind(ind *p_ind) /* Frees memory for given individual. */ { assert(p_ind != NULL); chk_free(p_ind->f_u); chk_free(p_ind->f_s); chk_free(p_ind); p_ind = NULL; } void free_obj(obj *objp ) /* Frees memory for given objective structure. */ { assert( objp != NULL ); if( objp->enabled != NULL ) chk_free(objp->enabled); if( objp->mapping != NULL ) chk_free(objp->mapping); chk_free(objp); objp = NULL; } void complete_free_pop(pop *pp) /* Frees memory for given population and for all individuals in the population. */ { int i = 0; if (pp != NULL) { if (pp->ind_array != NULL) { for (i = 0; i < pp->maxsize; i++) { if (pp->ind_array[i] != NULL) { free_ind(pp->ind_array[i]); pp->ind_array[i] = NULL; } } chk_free(pp->ind_array); pp->ind_array = NULL; } if( pp->obj ) free_obj( pp->obj ); if( pp->lowerbounds ) chk_free( pp->lowerbounds ); if( pp->upperbounds ) chk_free( pp->upperbounds ); chk_free(pp); pp = NULL; } } void create_front_part(fpart* partp, int max_pop_size) { int i; partp->max_fronts = (max_pop_size > 0 ? max_pop_size : 0); partp->fronts = 0; partp->size = 0; partp->front_array = (front*) chk_malloc(max_pop_size * sizeof(front)); for (i = 0; i < max_pop_size; i++) { partp->front_array[i].size = 0; partp->front_array[i].members = chk_malloc(max_pop_size * sizeof(int)); } } int getPopulationSize() { return pp_all->size; } pop* createExPop(int ind_to_create, int dim ) { pp_new = create_pop( ind_to_create, dim ); return pp_new; } void deleteExPop() { complete_free_pop( pp_new ); pp_new = NULL; } ind* create_ind(int dim) /* Allocates memory for one individual. */ { ind *p_ind; assert(dim >= 0); p_ind = (ind*) chk_malloc(sizeof(ind)); p_ind->index = -1; p_ind->fitness = -1; p_ind->dummy = -1; p_ind->f_u = (double*) chk_malloc(dim * sizeof(double)); p_ind->f_s = (double*) chk_malloc(dim * sizeof(double)); int i; for( i = 0; i < dim; i++ ) { p_ind->f_u[i] = -1; p_ind->f_s[i] = -1; } return (p_ind); } obj* create_obj(int dim) /* Allocates memory for the objective activity */ { obj *p_obj; p_obj = (obj*) chk_malloc(sizeof(obj)); assert( dim > 0); p_obj->enabled = (int*) chk_malloc(dim*sizeof(int)); p_obj->mapping = (int*) chk_malloc(dim*sizeof(int)); p_obj->nr_of_enabled_obj = -1; return (p_obj); } pop* create_pop(int ind_to_create, int dim ) /** Allocates memory for a population and creates ind_to_create individuals */ { int i; pop *pp; assert(dim >= 0); assert(ind_to_create >= 0); pp = (pop*) chk_malloc(sizeof(pop)); pp->maxsize = ind_to_create; pp->size = 0; pp->dim = dim; pp->obj = create_obj(dim); pp->lowerbounds = (double*) chk_malloc( sizeof(double)*dim ); pp->upperbounds = (double*) chk_malloc( sizeof(double)*dim ); for( i = 0; i < dim; i++ ) { pp->lowerbounds[i] = DBL_MAX; pp->upperbounds[i] = -DBL_MAX; } /** Enable all objective values by default */ for( i = 0; i < dim; i++ ) { pp->obj->enabled[i] = 1; pp->obj->mapping[i] = i; } pp->obj->nr_of_enabled_obj = dim; if( pp->maxsize > 0 ) { pp->ind_array = chk_malloc(pp->maxsize * sizeof(ind*)); for (i = 0; i < pp->maxsize; i++) pp->ind_array[i] = NULL; for( i = 0; i < ind_to_create; i++ ) pp->ind_array[i] = create_ind(dim); } else { pp->ind_array = NULL; } return (pp); } void updatePopulation(int sorting, fpart* curr_part, fpart* redu_part, fpart* repl_part, int ranking ) /* Updates the population pp_all and the partitions curr_part, redu_part and * repl_part */ { int i, j, k; int* popArray; const int popArray_size = pp_all->size + pp_new->size; popArray = chk_malloc(sizeof(int) * (popArray_size)); /* Adding the children to the main population */ for (i = 0; i < pp_new->size; i++) { pp_all->ind_array[pp_all->size] = pp_new->ind_array[i]; pp_all->size++; } /* Updating the partitions */ cleanPart(curr_part); for (i = pp_all->size - pp_new->size - 1; i >= 0; i--) insertInPart(curr_part, 0, i, sorting, ranking); cleanPart(redu_part); for (i = pp_all->size - 1; i >= 0; i--) insertInPart(redu_part, 0, i, sorting, ranking); if (sorting == 0) { cleanPart(repl_part); if( pp_all->size > popArray_size ) { fprintf(stderr,"popArray too small, exit\n"); } assert( pp_all->size <= popArray_size ); for (i = 0; i < pp_all->size; i++) popArray[i] = i; i = pp_all->size; for (j = alpha - pp_new->size; j > 0; j--) { k = irand(i); insertInPart(repl_part, 0, popArray[k], sorting, ranking); popArray[k] = popArray[--i]; } } else { copyPart(curr_part, repl_part); randomReduction(repl_part, alpha - pp_new->size); } /* Freeing the children's population and the popArray */ free_pop(pp_new); pp_new = NULL; chk_free(popArray); popArray = NULL; } void generatePartitions( int sorting, int ranking, fpart* curr_part, fpart* redu_part, fpart* repl_part ) { int* popArray; popArray = chk_malloc(sizeof(int) * (alpha + lambda)); int i, j, k; /* Add the old individuals to the partition used by heuristic reduction a */ copyPart(curr_part, redu_part); /* Add the old individuals to the partition used by replacement */ if (sorting == 0) { cleanPart(repl_part); for (i = 0; i < pp_all->size; i++) popArray[i] = i; i = pp_all->size; for (j = alpha - pp_new->size; j > 0; j--) { k = irand(i); insertInPart(repl_part, 0, popArray[k], sorting, ranking); popArray[k] = popArray[--i]; } } else { copyPart(curr_part, repl_part); randomReduction(repl_part, alpha - pp_new->size); } chk_free(popArray); popArray = NULL; } void removeIndividual( int sel, fpart* partp, front *fp ) { assert( sel >= 0 ); assert( sel < fp->size ); fp->size--; fp->members[sel] = fp->members[fp->size]; partp->size--; } void removeTheWorstIndividual(fpart* partp, front* fp ) { int j; int sel = 0; double min = DBL_MAX; for (j = fp->size - 1; j >= 0; j--) { if (min >= pp_all->ind_array[fp->members[j]]->fitness) { min = pp_all->ind_array[fp->members[j]]->fitness; sel = j; } } removeIndividual( sel, partp, fp ); } void removeTheWorstIndividualFromSet(fpart* partp, front* fp, int indices[], int indicesLength ) /* Removes the worst individual, that is in the set */ { int j, i; int sel = 0; double min = DBL_MAX; int found = 0; for (j = fp->size - 1; j >= 0; j--) { found = 0; for( i = 0; i < indicesLength; i++ ) { if( indices[i] == j ) found = 1; } if( found == 1 ) { if (min >= pp_all->ind_array[fp->members[j]]->fitness) { min = pp_all->ind_array[fp->members[j]]->fitness; sel = j; } } } removeIndividual(sel, partp, fp); } int removeTheWorstIndividualUnique(fpart* partp, front* fp, int indices[] ) /* Removes the worst individual form the population, if it is unique. * If not, the population remains as is, and the function returns the number * of individuals that share the same minimal value. contains the * indices of these individuals */ { int j; int sel = 0; double min = DBL_MAX; int unique = 0; int indicesIndex = 0; for (j = fp->size - 1; j >= 0; j--) { if( min == pp_all->ind_array[fp->members[j]]->fitness ) { unique = 0; indicesIndex++; indices[indicesIndex] = j; } if (min > pp_all->ind_array[fp->members[j]]->fitness) { min = pp_all->ind_array[fp->members[j]]->fitness; sel = j; unique = 1; indicesIndex = 0; indices[0] = j; } } if( unique ) { //fprintf(stderr,"Unique: %d\n", fp->members[sel]);fflush(stderr); //fprintf(stderr,"hat Werte (%f,%f)\n", getObjectiveValue(fp->members[sel],0 ), getObjectiveValue(fp->members[sel],1 ) ); //fprintf(stderr,"hat Fitness %f\n", pp_all->ind_array[fp->members[sel]]->fitness ); fp->size--; fp->members[sel] = fp->members[fp->size]; partp->size--; return 0; } else { //fprintf(stderr,"Not Unique!\n");fflush(stderr); return indicesIndex + 1; } } int getNrOfObjectives( ) { return pp_all->obj->nr_of_enabled_obj; } double getObjectiveValueDifference(int a, int b, int k) /* Calculates the difference of the k-th (enabled) objective values denoted * by the indices a (minuend) and b (subtrahend) */ { /* Get the indices of the desired objective */ assert( pp_all->obj->nr_of_enabled_obj > k ); assert( k >= 0 ); int i = pp_all->obj->mapping[k]; assert( i >= 0 && i < pp_all->dim ); assert( a >= 0 ); assert( a < pp_all->size ); assert( b >= 0 ); assert( b < pp_all->size ); return (pp_all->ind_array[a]->f_s[i] - pp_all->ind_array[b]->f_s[i] ); } double getObjectiveValueDifferenceUnscaled(int a, int b, int k) /* Calculates the difference of the k-th (enabled) objective values denoted * by the indices a (minuend) and b (subtrahend) * Uses the unscaled objective values, even if scaling is switched on */ { /* Get the indices of the desired objective */ assert( pp_all->obj->nr_of_enabled_obj > k ); assert( k >= 0 ); int i = pp_all->obj->mapping[k]; assert( i >= 0 && i < pp_all->dim ); assert( a >= 0 ); assert( a < pp_all->size ); assert( b >= 0 ); assert( b < pp_all->size ); return (pp_all->ind_array[a]->f_u[i] - pp_all->ind_array[b]->f_u[i] ); } double getObjectiveValue(int a, int k ) /* Returns the k-th (enabled) objective value denoted by the index a */ { assert( k >= 0 && k < pp_all->dim ); int i = pp_all->obj->mapping[k]; assert( i >= 0 && i < pp_all->dim ); assert( a >= 0 && a < pp_all->size ); return pp_all->ind_array[a]->f_s[i]; } double getReversedObjectiveValue(int a, int k, int scaling, double bound ) /* Returns the k-th (enabled) reversed objective value denoted by the index a*/ { int i = pp_all->obj->mapping[k]; assert( i >= 0 && i <= pp_all->dim ); if( scaling > 0 ) { if( bound <= pp_all->ind_array[a]->f_s[i] ) { fprintf(stderr,"The objective value exceeds the bounds! "); fprintf(stderr,"You enabled scaling, the bounds must be at least "); fprintf(stderr,"1 in this case, your choice was %f\n",bound); return 0; } return bound - pp_all->ind_array[a]->f_s[i]; } else { if( bound <= pp_all->ind_array[a]->f_u[i] ) { fprintf(stderr,"The objective value exceeds the bounds! "); fprintf(stderr,"value: %lf, bound: %lf\n", pp_all->ind_array[a]->f_u[i], bound ); return 0; } return bound - pp_all->ind_array[a]->f_u[i]; } } void getObjectiveVector( int* A, int sizea, int k, double* objVect ) /* Returns a vector of the kth objectives referenced by A */ { int i; for( i = 0; i < sizea; i++ ) objVect[i] = getObjectiveValue(A[i],k); } void getObjectiveArray( int* A, int sizea, double* pointArray ) /* Returns an array of all objectives referenced by A */ { int nr_of_objectives = pp_all->obj->nr_of_enabled_obj; int i,k; for( i = 0; i < sizea; i++ ) { for( k = 0; k < nr_of_objectives; k++ ) { pointArray[ i*nr_of_objectives + k ] = getObjectiveValue(A[i],k); } } } void create_population() { /* create individual and archive pop */ pp_all = create_pop(alpha + lambda, dim); pp_sel = create_pop(mu, dim); pp_sel->size = mu; return; } void free_populations() { complete_free_pop(pp_all); if( pp_sel ) { chk_free(pp_sel->ind_array); pp_sel->ind_array = NULL; if( pp_sel->obj ) free_obj( pp_sel->obj ); if( pp_sel->lowerbounds ) chk_free( pp_sel->lowerbounds ); if( pp_sel->upperbounds ) chk_free( pp_sel->upperbounds ); chk_free(pp_sel); pp_sel = NULL; } complete_free_pop(pp_new); pp_sel = NULL; pp_all = NULL; pp_new = NULL; } void addToSelection(int i, int c ) { assert( 0 <= i ); assert( i < pp_sel->size ); assert( 0 <= c ); assert( c < pp_all->size ); pp_sel->ind_array[i] = pp_all->ind_array[c]; } void copyExPopToArcPop(int sorting, int ranking, fpart* curr_part ) { int i; for (i = 0; i < pp_new->size; i++) { assert( pp_all->size < pp_all->maxsize ); pp_all->ind_array[pp_all->size] = pp_new->ind_array[i]; pp_all->size++; insertInPart(curr_part, 0, pp_all->size - 1, sorting, ranking); } free_pop(pp_new); pp_new = NULL; } pop* getSelPop() { return pp_sel; } pop* getArcPop() { return pp_all; } int getArcSize() { return pp_all->size; } void setAllPopSize( int size ) { pp_all->size = size; }