/*******************************************************************************/ /* GKLS-Generator of Classes of ND (non-differentiable), */ /* D (continuously differentiable), and */ /* D2 (twice continuously differentiable) */ /* Test Functions for Global Optimization */ /* */ /* Authors: */ /* */ /* M.Gaviano, D.E.Kvasov, D.Lera, and Ya.D.Sergeyev */ /* */ /* (C) 2002-2003 */ /* */ /* Each test class is defined by the following parameters: */ /* (1) problem dimension */ /* (2) number of local minima including paraboloid min and global min */ /* (3) global minimum value */ /* (3) distance from the paraboloid vertex to the global minimizer */ /* (4) radius of the attraction region of the global minimizer */ /*******************************************************************************/ /*******************************************************************************/ /* The following groups of subroutines are present in the software: */ /* -- parameters setting/checking subroutines: */ /* int GKLS_set_default (void); */ /* int GKLS_parameters_check (void); */ /* -- test classes generating subroutines: */ /* int GKLS_arg_generate (unsigned int); */ /* int GKLS_coincidence_check (void); */ /* int GKLS_set_basins (void); */ /* -- test functions calling subroutines: */ /* double GKLS_ND_func (double *); */ /* double GKLS_D_func (double *); */ /* double GKLS_D2_func (double *); */ /* -- subroutines of evaluation of the partial derivatives of test functions */ /* double GKLS_D_deriv (unsigned int, double *); */ /* double GKLS_D2_deriv1 (unsigned int, double *); */ /* double GKLS_D2_deriv2 (unsigned int, unsigned int, double *); */ /* -- subroutines of evaluation of the gradients and hessian matrix */ /* int GKLS_D_gradient (double *, double *); */ /* int GKLS_D2_gradient (double *, double *); */ /* int GKLS_D2_hessian (double *, double **); */ /* -- memory allocation/deallocation subroutines: */ /* int GKLS_domain_alloc (void); / void GKLS_domain_free (void); */ /* int GKLS_alloc (void); / void GKLS_free (void); */ /* -- auxiliary subroutines */ /* int GKLS_initialize_rnd (unsigned int, unsigned int, int); */ /* double GKLS_norm (double *, double *); */ /*******************************************************************************/ #include "gkls.h" #include "rnd_gen.h" #include #include #include /*---------------- Variables accessible by the user -------------------- */ double *GKLS_domain_left; /* left boundary vector of D */ /* D=[GKLS_domain_left; GKLS_domain_ight] */ double *GKLS_domain_right;/* right boundary vector of D */ unsigned int GKLS_dim; /* dimension of the problem, */ /* 2<=GKLS_dim=2 */ double GKLS_global_dist; /* distance from the paraboloid minimizer */ /* to the global minimizer */ double GKLS_global_radius;/* radius of the global minimizer */ /* attraction region */ double GKLS_global_value; /* global minimum value, */ /* GKLS_global_value < GKLS_PARABOLOID_MIN */ T_GKLS_Minima GKLS_minima; /* see the structures type description */ T_GKLS_GlobalMinima GKLS_glob; /*--------------------------- Global variables ----------------------*/ int isArgSet=0; /* isArgSet == 1 if all necessary parameters are set */ double delta; /* parameter using in D2-type function generation; */ /* it is chosen randomly from the */ /* open interval (0,GKLS_DELTA_MAX_VALUE) */ unsigned long rnd_counter; /* index of random array elements */ /*------------------ Auxiliary functions prototypes -----------------*/ double GKLS_norm(double *, double *); int GKLS_alloc(void); int GKLS_coincidence_check(void); int GKLS_set_basins(void); int GKLS_initialize_rnd(unsigned int, unsigned int, int); /*****************************************************************************/ /* Distance between two vectors in the Euclidean space R^(GKLS_dim) */ /* INPUT: */ /* x1, x2 -- arrays of the coordinates of the two vectors x1 and x2 */ /* of the dimension GKLS_dim */ /* RETURN VALUE: Euclidean norm ||x1-x2|| */ /*****************************************************************************/ double GKLS_norm(double *x1, double *x2) { unsigned int i; double norm = 0.0; for (i=0; i= NUM_RND) ) return GKLS_DIM_ERROR; /* problem dimension error */ if ((GKLS_domain_left = (double *)(malloc((size_t)GKLS_dim*sizeof(double)))) == NULL) return GKLS_MEMORY_ERROR; /* memory allocation error */ if ((GKLS_domain_right =(double *)(malloc((size_t)GKLS_dim*sizeof(double)))) == NULL) return GKLS_MEMORY_ERROR; /* memory allocation error */ /* Set the admissible region as [-1,1]^GKLS_dim */ for (i=0; i= NUM_RND) ) return GKLS_DIM_ERROR; /* problem dimension error */ if (GKLS_num_minima <= 1) return GKLS_NUM_MINIMA_ERROR; /* erroneous number of local minima */ if ((GKLS_minima.local_min =(double **)(malloc((size_t)GKLS_num_minima*sizeof(double *)))) == NULL) return GKLS_MEMORY_ERROR; /* memory allocation error */ for (i=0; i= NUM_RND)) return GKLS_DIM_ERROR; /* problem dimension errors */ if (GKLS_num_minima <= 1) /* number of local minima error */ return GKLS_NUM_MINIMA_ERROR; if ((GKLS_domain_left == NULL) || (GKLS_domain_right == NULL)) return GKLS_BOUNDARY_ERROR; /* the boundaries are not defined */ for (i=0; i= GKLS_domain_right[i] - GKLS_PRECISION) return GKLS_BOUNDARY_ERROR; /* the boundaries are erroneous */ if (GKLS_global_value >= GKLS_PARABOLOID_MIN - GKLS_PRECISION) return GKLS_GLOBAL_MIN_VALUE_ERROR; /* the global minimum value must */ /* be less than the paraboloid min */ /* Find min_side = min |b(i)-a(i)|, D=[a,b], and */ /* check the distance from paraboloid vertex to global minimizer */ min_side = GKLS_domain_right[0]-GKLS_domain_left[0]; for (i=1; i= 0.5*min_side - GKLS_PRECISION) || (GKLS_global_dist <= GKLS_PRECISION) ) return GKLS_GLOBAL_DIST_ERROR; /* global distance error */ if ( (GKLS_global_radius >= 0.5*GKLS_global_dist + GKLS_PRECISION) || (GKLS_global_radius <= GKLS_PRECISION) ) return GKLS_GLOBAL_RADIUS_ERROR; /* global minimizer attr. radius error */ return GKLS_OK; /* no errors */ } /* GKLS_parameters_check() */ /*****************************************************************************/ /* The subroutine checks possible coincidence of local minimizers */ /* The subroutine has no INPUT parameters */ /* RETURN VALUE: an error code (GKLS_OK if there are no errors): */ /* GKLS_PARABOLA_MIN_COINCIDENCE_ERROR - if some local minimizer coincides */ /* with the paraboloid minimizer */ /* GKLS_LOCAL_MIN_COINCIDENCE_ERRO - if there is a pair of identical */ /* local minimizers */ /*****************************************************************************/ int GKLS_coincidence_check() { unsigned int i, j; /* Check wether some local minimizer coincides with the paraboloid minimizer */ for (i=2; i GKLS_minima.rho[i] + GKLS_PRECISION) GKLS_minima.rho[i] = temp_min; } } /* Correct the radii by weight coefficients w(i) */ /* The weight coefficients can be chosen randomly; */ /* here they are defined by default as: */ /* w(i) = 0.99, i != 1 , and w(1) = 1.0 (global min index = 1) */ for (i=0; i= 2 */ /* Note that peak(i) is such that the function value f(i) is smaller*/ /* than min(GKLS_GLOBAL_MIN_VALUE, 2*rho(i)) */ temp_d1=GKLS_norm(GKLS_minima.local_min[0], GKLS_minima.local_min[i]); temp_min=(GKLS_minima.rho[i] - temp_d1)*(GKLS_minima.rho[i] - temp_d1)+ GKLS_minima.f[0]; /*the conditional minimum at the boundary*/ temp_d1 = (1.0 + rnd_num[rnd_counter])*GKLS_minima.rho[i]; temp_d2 = rnd_num[rnd_counter]*(temp_min - GKLS_global_value); /* temp_d1 := min(temp_d1, temp_d2) */ if (temp_d2 < temp_d1) temp_d1 = temp_d2; GKLS_minima.peak[i]= temp_d1; rnd_counter++; if (rnd_counter == NUM_RND) { ranf_array(rnd_num, NUM_RND); rnd_counter = 0L; } GKLS_minima.f[i] = temp_min - GKLS_minima.peak[i]; } /*********************************************************************/ /* Find all possible global minimizers and */ /* create a list of their indices among all the minimizers */ /* Note that the paraboloid minimum can not be the global one because*/ /* the global optimum value is set to be less than the paraboloid */ /* minimum value */ /*********************************************************************/ GKLS_glob.num_global_minima = 0; for (i=0; i= GKLS_global_value - GKLS_PRECISION) && (GKLS_minima.f[i] <= GKLS_global_value + GKLS_PRECISION)) { GKLS_glob.gm_index[GKLS_glob.num_global_minima] = i; GKLS_glob.num_global_minima ++; /* The first GKLS_glob.num_global_minima elements of the list */ /* contain the indices of the global minimizers */ } else GKLS_glob.gm_index[GKLS_num_minima-1-i+GKLS_glob.num_global_minima] = i; /* The remaining elements of the list */ /* contain the indices of local (non global) minimizers */ if (GKLS_glob.num_global_minima == 0) /* erroneous case: */ return GKLS_FLOATING_POINT_ERROR; /* some programmer's error */ return GKLS_OK; } /* GKLS_set_basins() */ /*****************************************************************************/ /* The subroutine initializes random sequence by generating a seed that */ /* depends on a specific test function number, on the number of local minima,*/ /* and on the problem dimension */ /* INPUT PARAMETERS: */ /* dim -- dimension of the problem (dim >= 2); */ /* nmin -- number of local minima (nmin >= 2); */ /* nf -- test function number (from 1 to 100) */ /* RETURN VALUE: normally GKLS_OK */ /*****************************************************************************/ int GKLS_initialize_rnd(unsigned int dim, unsigned int nmin, int nf) { long seed; /* seed number between 0 and 2^30-3 = 1,073,741,821*/ seed = (nf-1) + (nmin-1)*100 + dim*1000000L; /* If big values of nmin and dim are required, */ /* one must check wether seed <= 1073741821 */ ranf_start(seed); return GKLS_OK; } /* GKLS_initialize_rnd() */ /*****************************************************************************/ /* The main subroutine of the package that generates randomly the local and */ /* the global minimizers and function values at minimizers; */ /* it determines the radii of attraction regions of the minimizers */ /* INPUT PARAMETER: */ /* nf -- determines the number of test function, 1 <= nf <= 100 */ /* RETURN VALUE: */ /* an error code */ /* The boundaries vectors should be created and */ /* the parameters of the class should be defined first */ /*****************************************************************************/ int GKLS_arg_generate (unsigned int nf) { unsigned int i, j; int error; double sin_phi; /* for generating of the global minimizer coordinates */ /* by using the generalized spherical coordinates */ double gap = GKLS_global_radius; /* gap > 0 */ /* the minimal distance of any local minimizer to the attraction*/ /* region of the global minimizer M(1); the value */ /* GKLS_global_radius is given by default and can be changed, */ /* but it should not be too small. */ /* Check function number */ if ((nf < 1) || (nf > 100)) return GKLS_FUNC_NUMBER_ERROR; /* Check parameters */ if ( (error = GKLS_parameters_check()) != GKLS_OK) return error; /* Allocate memory */ if ( (error = GKLS_alloc()) != GKLS_OK) return error; /* Set random seed */ if ( (error = GKLS_initialize_rnd(GKLS_dim,GKLS_num_minima,nf)) != GKLS_OK) return error; ranf_array(rnd_num, NUM_RND); /* get random sequence */ rnd_counter = 0L; /* index of the random element from the sequence */ /* to be used as the next random number */ /* Set the paraboloid minimizer coordinates and */ /* the paraboloid minimum value */ for (i=0; i GKLS_domain_right[0] - GKLS_PRECISION) || (GKLS_minima.local_min[1][0] < GKLS_domain_left[0] + GKLS_PRECISION) ) GKLS_minima.local_min[1][0] = GKLS_minima.local_min[0][0] - GKLS_global_dist*cos(PI*rnd_num[rnd_counter]); sin_phi = sin(PI*rnd_num[rnd_counter]); rnd_counter++; /* Generate the remaining angles 0<=phi(i)<=2*PI, and */ /* the coordinates x(i), i=1,...,GKLS_dim-2 (not last!) */ for(j=1; j GKLS_domain_right[j] - GKLS_PRECISION) || (GKLS_minima.local_min[1][j] < GKLS_domain_left[j] + GKLS_PRECISION) ) GKLS_minima.local_min[1][j] = GKLS_minima.local_min[0][j] - GKLS_global_dist*cos(2.0*PI*rnd_num[rnd_counter])*sin_phi; sin_phi *= sin(2.0*PI*rnd_num[rnd_counter]); rnd_counter++; } /* Generate the last coordinate x(GKLS_dim-1) */ GKLS_minima.local_min[1][GKLS_dim-1] = GKLS_minima.local_min[0][GKLS_dim-1] + GKLS_global_dist*sin_phi; if ( (GKLS_minima.local_min[1][GKLS_dim-1] > GKLS_domain_right[GKLS_dim-1] - GKLS_PRECISION) || (GKLS_minima.local_min[1][GKLS_dim-1] < GKLS_domain_left[GKLS_dim-1] + GKLS_PRECISION) ) GKLS_minima.local_min[1][GKLS_dim-1] = GKLS_minima.local_min[0][GKLS_dim-1] - GKLS_global_dist*sin_phi; /* Set the global minimum value */ GKLS_minima.f[1] = GKLS_global_value; /* Set the weight coefficients w_rho(i) */ for (i=0; i GKLS_PRECISION ); i++; } error = GKLS_coincidence_check(); } while ( (error == GKLS_PARABOLA_MIN_COINCIDENCE_ERROR) || (error == GKLS_LOCAL_MIN_COINCIDENCE_ERROR) ); error = GKLS_set_basins(); if (error == GKLS_OK) isArgSet = 1; /* All the parameters are set */ /* and the user can evaluate a specific test function or */ /* its partial derivative by calling corresponding subroutines */ return error; } /* GKLS_arg_generate () */ /************************************************************************/ /* The subroutine evaluates the generated function */ /* of the ND-type (non-differentiable) */ /* */ /* INPUT PARAMETER: */ /* x -- a point of the (GKLS_dim)-dimensional euclidean space */ /* RETURN VALUE: */ /* a function value OR */ /* GKLS_MAX_VALUE if: (1) the vector x does not belong to D; */ /* (2) the user tries to call the function without */ /* parameter defining */ /************************************************************************/ double GKLS_ND_func(double *x) { unsigned int i, index; double norm, scal, a, rho; /* working variables */ if (!isArgSet) return GKLS_MAX_VALUE; for (i=0; i GKLS_domain_right[i]+GKLS_PRECISION) ) return GKLS_MAX_VALUE; /* Check wether x belongs to some basin of local minima, M(index) <> T */ /* Attention: number of local minima must be >= 2 */ index = 1; while ((index GKLS_minima.rho[index]) ) index++; if (index == GKLS_num_minima) { norm = GKLS_norm(GKLS_minima.local_min[0],x); /* Return the value of the paraboloid function */ return (norm * norm + GKLS_minima.f[0]); } /* Check wether x coincides with the local minimizer M(index) */ if ( GKLS_norm(x, GKLS_minima.local_min[index]) < GKLS_PRECISION ) return GKLS_minima.f[index]; norm = GKLS_norm(GKLS_minima.local_min[0],GKLS_minima.local_min[index]); a = norm * norm + GKLS_minima.f[0] - GKLS_minima.f[index]; rho = GKLS_minima.rho[index]; norm = GKLS_norm(GKLS_minima.local_min[index],x); scal = 0.0; for(i=0; i GKLS_domain_right[i]+GKLS_PRECISION) ) return GKLS_MAX_VALUE; /* Check wether x belongs to some basin of local minima, M(index) <> T */ /* Attention: number of local minima must be >= 2 */ index = 1; while ((index GKLS_minima.rho[index]) ) index++; if (index == GKLS_num_minima) { norm = GKLS_norm(GKLS_minima.local_min[0],x); /* Return the value of the paraboloid function */ return (norm * norm + GKLS_minima.f[0]); } /* Check wether x coincides with the local minimizer M(index) */ if ( GKLS_norm(x, GKLS_minima.local_min[index]) < GKLS_PRECISION ) return GKLS_minima.f[index]; norm = GKLS_norm(GKLS_minima.local_min[0],GKLS_minima.local_min[index]); a = norm * norm + GKLS_minima.f[0] - GKLS_minima.f[index]; rho = GKLS_minima.rho[index]; norm = GKLS_norm(GKLS_minima.local_min[index],x); scal = 0.0; for(i=0; i GKLS_domain_right[i] + GKLS_PRECISION) ) return GKLS_MAX_VALUE; /* Check wether x belongs to some basin of local minima */ index = 1; while ((index GKLS_minima.rho[index]) ) index++; if (index == GKLS_num_minima) { norm = GKLS_norm(GKLS_minima.local_min[0],x); /* Return the value of the paraboloid function */ return (norm * norm + GKLS_minima.f[0]); } /* Check wether x coincides with the local minimizer M(index) */ if ( GKLS_norm(x, GKLS_minima.local_min[index]) < GKLS_PRECISION ) return GKLS_minima.f[index]; norm = GKLS_norm(GKLS_minima.local_min[0],GKLS_minima.local_min[index]); a = norm * norm + GKLS_minima.f[0] - GKLS_minima.f[index]; rho = GKLS_minima.rho[index]; norm = GKLS_norm(GKLS_minima.local_min[index],x); scal = 0.0; for(i=0; i GKLS_dim) ) return GKLS_MAX_VALUE; else var_j = var_j - 1; /* to be used as an index of array */ if (!isArgSet) return GKLS_MAX_VALUE; for (i=0; i GKLS_domain_right[i]+GKLS_PRECISION) ) return GKLS_MAX_VALUE; /* Check wether x belongs to some basin of local minima, M(index) <> T */ /* Attention: number of local minima must be >= 2 */ index = 1; while ((index GKLS_minima.rho[index]) ) index++; if (index == GKLS_num_minima) { /* Return the value of the first order partial derivative of the paraboloid function */ return 2.0*(x[var_j]-GKLS_minima.local_min[0][var_j]); } /* Check wether x coincides with the local minimizer M(index) */ if ( GKLS_norm(x, GKLS_minima.local_min[index]) < GKLS_PRECISION ) return 0.0; norm = GKLS_norm(GKLS_minima.local_min[0],GKLS_minima.local_min[index]); a = norm * norm + GKLS_minima.f[0] - GKLS_minima.f[index]; rho = GKLS_minima.rho[index]; norm = GKLS_norm(GKLS_minima.local_min[index],x); scal = 0.0; for(i=0; i GKLS_dim) ) return GKLS_MAX_VALUE; else var_j = var_j - 1; /* to be used as an index of array */ if (!isArgSet) return GKLS_MAX_VALUE; for (i=0; i GKLS_domain_right[i]+GKLS_PRECISION) ) return GKLS_MAX_VALUE; /* Check wether x belongs to some basin of local minima, M(index) <> T */ /* Attention: number of local minima must be >= 2 */ index = 1; while ((index GKLS_minima.rho[index]) ) index++; if (index == GKLS_num_minima) { /* Return the value of the first order partial derivative of the paraboloid function */ return 2.0*(x[var_j]-GKLS_minima.local_min[0][var_j]); } /* Check wether x coincides with the local minimizer M(index) */ if ( GKLS_norm(x, GKLS_minima.local_min[index]) < GKLS_PRECISION ) return 0.0; norm = GKLS_norm(GKLS_minima.local_min[0],GKLS_minima.local_min[index]); a = norm * norm + GKLS_minima.f[0] - GKLS_minima.f[index]; rho = GKLS_minima.rho[index]; norm = GKLS_norm(GKLS_minima.local_min[index],x); scal = 0.0; for(i=0; i GKLS_dim) ) return GKLS_MAX_VALUE; if ( (var_k == 0) || (var_k > GKLS_dim) ) return GKLS_MAX_VALUE; the_same = (var_j == var_k); var_j = var_j - 1; var_k = var_k - 1; /* to be used as indexes of array */ if (!isArgSet) return GKLS_MAX_VALUE; for (i=0; i GKLS_domain_right[i]+GKLS_PRECISION) ) return GKLS_MAX_VALUE; /* Check wether x belongs to some basin of local minima, M(index) <> T */ /* Attention: number of local minima must be >= 2 */ index = 1; while ((index GKLS_minima.rho[index]) ) index++; if (index == GKLS_num_minima) { /* Return the value of the second order partial derivative of the paraboloid function */ if (the_same) return 2.0; else return 0.0; } /* Check wether x coincides with the local minimizer M(index) */ if ( GKLS_norm(x, GKLS_minima.local_min[index]) < GKLS_PRECISION ) { if (the_same) return delta; else return 0.0; } norm = GKLS_norm(GKLS_minima.local_min[0],GKLS_minima.local_min[index]); a = norm * norm + GKLS_minima.f[0] - GKLS_minima.f[index]; rho = GKLS_minima.rho[index]; norm = GKLS_norm(GKLS_minima.local_min[index],x); scal = 0.0; for(i=0; i= GKLS_MAX_VALUE-1000.0) error_code = GKLS_DERIV_EVAL_ERROR; } return error_code; } /* GKLS_D_gradient() */ /*******************************************************************************/ /* The subroutine evaluates the gradient of the D2-type test function */ /* INPUT PARAMETERS: */ /* x -- a point of the (GKLS_dim)-dimensional euclidean space */ /* g -- a pointer to the allocated array of the dimension GKLS_dim */ /* RETURN VALUES: */ /* an error code (that can be: GKLS_OK -- no error, or */ /* GKLS_DERIV_EVAL_ERROR -- otherwise) */ /* g -- a pointer to the array of gradient coordinates */ /*******************************************************************************/ int GKLS_D2_gradient (double *x, double *g) { unsigned int i; int error_code = GKLS_OK; if (!isArgSet) return GKLS_DERIV_EVAL_ERROR; if (g == NULL) return GKLS_DERIV_EVAL_ERROR; for (i=1; i<=GKLS_dim; i++) { g[i-1] = GKLS_D2_deriv1(i,x); if (g[i-1] >= GKLS_MAX_VALUE-1000.0) error_code = GKLS_DERIV_EVAL_ERROR; } return error_code; } /* GKLS_D2_gradient() */ /*******************************************************************************/ /* The subroutine evaluates the Hessian matrix of the D2-type test function */ /* INPUT PARAMETERS: */ /* x -- a point of the (GKLS_dim)-dimensional euclidean space */ /* h -- a pointer to the allocated matrix of dimension[GKLS_dim,GKLS_dim] */ /* RETURN VALUES: */ /* an error code (that can be: GKLS_OK -- no error, or */ /* GKLS_DERIV_EVAL_ERROR -- otherwise */ /* h -- a pointer to the Hessian matrix */ /*******************************************************************************/ int GKLS_D2_hessian (double *x, double **h) { unsigned int i, j; int error_code = GKLS_OK; if (!isArgSet) return GKLS_DERIV_EVAL_ERROR; if (h == NULL) return GKLS_DERIV_EVAL_ERROR; for (i=1; i<=GKLS_dim; i++) if (h[i-1] == NULL) return GKLS_DERIV_EVAL_ERROR; for (i=1; i<=GKLS_dim; i++) for (j=1; j<=GKLS_dim; j++) { h[i-1][j-1] = GKLS_D2_deriv2(i,j,x); if (h[i-1][j-1] >= GKLS_MAX_VALUE-1000.0) error_code = GKLS_DERIV_EVAL_ERROR; } return error_code; } /* GKLS_D2_hessian() */ /****************************** gkls.c ******************************/