void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { const mxArray *MatlabFunctionHandle; direct_algorithm theAlgorithm=DIRECT_ORIGINAL; const direct_objective_func f=&MatlabCallback; size_t numDim; double *lowerBounds; double *upperBounds; int maxFEval=500; int maxIter=100; double epsilon=1e-4; double epsilonAbs=0; double volumeRelTol=1e-10; double sigmaRelTol=0; double fGlobal=DIRECT_UNKNOWN_FGLOBAL; double fGlobalRelTol=DIRECT_UNKNOWN_FGLOBAL; int maxDiv=5000; //To hold return values direct_return_code retVal; double *x; double fVal; if(nrhs<3||nrhs>4){ mexErrMsgTxt("Wrong number of inputs"); } if(nlhs>3) { mexErrMsgTxt("Wrong number of outputs."); } //Check that a function handle was passed. if(!mxIsClass(prhs[0],"function_handle")) { mexErrMsgTxt("The first input must be a function handle."); } MatlabFunctionHandle=prhs[0]; //Check the lower and upper bounds checkRealDoubleArray(prhs[1]); checkRealDoubleArray(prhs[2]); numDim=mxGetM(prhs[1]); if(numDim<1||mxGetN(prhs[1])!=1) { mexErrMsgTxt("The lower bounds have the wrong dimensionality."); } if(mxGetM(prhs[2])!=numDim||mxGetN(prhs[1])!=1) { mexErrMsgTxt("The upper bounds have the wrong dimensionality."); } //The function in the library only uses integers for dimensions. if(numDim>INT_MAX) { mexErrMsgTxt("The problem has too many dimensions to be solved using this function."); } lowerBounds=(double*)mxGetData(prhs[1]); upperBounds=(double*)mxGetData(prhs[2]); //If a structure of options was given if(nrhs>3&&!mxIsEmpty(prhs[3])) { //We have to check for every possible structure member. mxArray *theField; if(!mxIsStruct(prhs[3])) { mexErrMsgTxt("The options must be given in a structure."); } theField=mxGetField(prhs[3],0,"algorithm"); if(theField!=NULL) {//If the field is present. int algType=getIntFromMatlab(theField); //Algorithm type switch(algType) { case 0: theAlgorithm=DIRECT_ORIGINAL; break; case 1: theAlgorithm=DIRECT_GABLONSKY; break; default: mexErrMsgTxt("Invalid algorithm specified"); } } theField=mxGetField(prhs[3],0,"maxDiv"); if(theField!=NULL) {//If the field is present. maxDiv=getIntFromMatlab(theField); if(maxDiv<1) { mexErrMsgTxt("Invalid maxDiv specified"); } } theField=mxGetField(prhs[3],0,"maxIter"); if(theField!=NULL) {//If the field is present. maxIter=getIntFromMatlab(theField); if(maxIter<1) { mexErrMsgTxt("Invalid maxIter specified"); } } theField=mxGetField(prhs[3],0,"maxFEval"); if(theField!=NULL) {//If the field is present. maxFEval=getIntFromMatlab(theField); if(maxIter<1) { mexErrMsgTxt("Invalid maxFEval specified"); } } theField=mxGetField(prhs[3],0,"epsilon"); if(theField!=NULL) {//If the field is present. epsilon=getDoubleFromMatlab(theField); if(fabs(epsilon)>=1) { mexErrMsgTxt("Invalid epsilon specified"); } } theField=mxGetField(prhs[3],0,"epsilonAbs"); if(theField!=NULL) {//If the field is present. epsilonAbs=getDoubleFromMatlab(theField); if(epsilonAbs>=1||epsilonAbs<0) { mexErrMsgTxt("Invalid epsilonAbs specified"); } } theField=mxGetField(prhs[3],0,"volumeRelTol"); if(theField!=NULL) {//If the field is present. volumeRelTol=getDoubleFromMatlab(theField); if(volumeRelTol>=1||volumeRelTol<0) { mexErrMsgTxt("Invalid volumeRelTol specified"); } } theField=mxGetField(prhs[3],0,"sigmaRelTol"); if(theField!=NULL) {//If the field is present. sigmaRelTol=getDoubleFromMatlab(theField); if(sigmaRelTol>=1||sigmaRelTol<0) { mexErrMsgTxt("Invalid sigmaRelTol specified"); } } theField=mxGetField(prhs[3],0,"fGlobal"); if(theField!=NULL) {//If the field is present. fGlobal=getDoubleFromMatlab(theField); fGlobalRelTol=1e-12;//Default value if fGlobal is given. } theField=mxGetField(prhs[3],0,"fGlobalRelTol"); if(theField!=NULL) {//If the field is present. fGlobalRelTol=getDoubleFromMatlab(theField); if(fGlobalRelTol<0) { mexErrMsgTxt("Invalid fGlobalRelTol specified"); } } } //Allocate space for the return values x=mxCalloc(numDim, sizeof(double)); retVal=direct_optimize(f,//Objective function pointer (void*)MatlabFunctionHandle,//Data that passed to the objective function. Here, the function handle passed by the user. (int)numDim,//The dimensionality of the problem lowerBounds,//Array of the lower bound of each dimension. upperBounds,//Array of the upper bound of each dimension. x,//An array that will be set to the optimum value on return. &fVal,//On return, set to the minimum value. maxFEval,//Maximum number of function evaluations. maxIter,//Maximum number of iterations epsilon,//Jones' epsilon parameter (1e-4 is recommended) epsilonAbs,//An absolute version of magic_eps //Relative tolerance on the hypercube volume (use 0 if none). This is //a percentage (0-1) of the volume of the original hypercube volumeRelTol, //Relative tolerance on the hypercube measure (0 if none) sigmaRelTol, //A pointer to a variable that can terminate the optimization. This is //in the library's code so that an external thread can write to this //and force the optimization to stop. Here, we are not using it, so we //can pass NULL. NULL, fGlobal,//Function value of the global optimum, if known. Use DIRECT_UNKNOWN_FGLOBAL if unknown. fGlobalRelTol,//Relative tolerance for convergence if fglobal is known. If unknown, use DIRECT_UNKNOWN_FGLOBAL. NULL,//There is no output to a file. theAlgorithm,//The algorithm to use maxDiv);//The maximum number of hyperrectangle divisions //If an error occurred if(retVal<0) { mxFree(x); switch(retVal){ case DIRECT_INVALID_BOUNDS: mexErrMsgTxt("Upper bounds are <= lower bounds for one or more dimensions."); case DIRECT_MAXFEVAL_TOOBIG: mexErrMsgTxt("maxFEval is too large."); case DIRECT_INIT_FAILED: mexErrMsgTxt("An initialization step failed."); case DIRECT_SAMPLEPOINTS_FAILED: mexErrMsgTxt("An error occurred creating sampling points."); case DIRECT_SAMPLE_FAILED: mexErrMsgTxt("An error occurred while sampling the function."); case DIRECT_OUT_OF_MEMORY: mexErrMsgTxt("Out of memory"); case DIRECT_INVALID_ARGS: mexErrMsgTxt("Invalid arguments provided"); //These errors should not occur either because they should //never be called or because retVal>=0 so these are not //actually errors. case DIRECT_FORCED_STOP: case DIRECT_MAXFEVAL_EXCEEDED: case DIRECT_MAXITER_EXCEEDED: case DIRECT_GLOBAL_FOUND: case DIRECT_VOLTOL: case DIRECT_SIGMATOL: case DIRECT_MAXTIME_EXCEEDED: default: mexErrMsgTxt("An unknown error occurred."); } } //Set the return values plhs[0]=mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL); mxFree(mxGetPr(plhs[0])); mxSetPr(plhs[0], x); mxSetM(plhs[0], numDim); mxSetN(plhs[0], 1); if(nlhs>1) { plhs[1]=doubleMat2Matlab(&fVal,1,1); if(nlhs>2) { plhs[2]=intMat2MatlabDoubles(&retVal,1,1); } } }
/* unlike nlopt_optimize() below, only handles minimization case */ static nlopt_result nlopt_optimize_(nlopt_opt opt, double *x, double *minf) { const double *lb, *ub; nlopt_algorithm algorithm; nlopt_func f; void *f_data; unsigned n, i; int ni; nlopt_stopping stop; if (!opt || !x || !minf || !opt->f || opt->maximize) return NLOPT_INVALID_ARGS; /* reset stopping flag */ nlopt_set_force_stop(opt, 0); opt->force_stop_child = NULL; /* copy a few params to local vars for convenience */ n = opt->n; ni = (int) n; /* most of the subroutines take "int" arg */ lb = opt->lb; ub = opt->ub; algorithm = opt->algorithm; f = opt->f; f_data = opt->f_data; if (n == 0) { /* trivial case: no degrees of freedom */ *minf = opt->f(n, x, NULL, opt->f_data); return NLOPT_SUCCESS; } *minf = HUGE_VAL; /* make sure rand generator is inited */ nlopt_srand_time_default(); /* default is non-deterministic */ /* check bound constraints */ for (i = 0; i < n; ++i) if (lb[i] > ub[i] || x[i] < lb[i] || x[i] > ub[i]) return NLOPT_INVALID_ARGS; stop.n = n; stop.minf_max = opt->stopval; stop.ftol_rel = opt->ftol_rel; stop.ftol_abs = opt->ftol_abs; stop.xtol_rel = opt->xtol_rel; stop.xtol_abs = opt->xtol_abs; stop.nevals = 0; stop.maxeval = opt->maxeval; stop.maxtime = opt->maxtime; stop.start = nlopt_seconds(); stop.force_stop = &(opt->force_stop); switch (algorithm) { case NLOPT_GN_DIRECT: case NLOPT_GN_DIRECT_L: case NLOPT_GN_DIRECT_L_RAND: if (!finite_domain(n, lb, ub)) return NLOPT_INVALID_ARGS; return cdirect(ni, f, f_data, lb, ub, x, minf, &stop, 0.0, (algorithm != NLOPT_GN_DIRECT) + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 2 : (algorithm != NLOPT_GN_DIRECT)) + 9 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 1 : (algorithm != NLOPT_GN_DIRECT))); case NLOPT_GN_DIRECT_NOSCAL: case NLOPT_GN_DIRECT_L_NOSCAL: case NLOPT_GN_DIRECT_L_RAND_NOSCAL: if (!finite_domain(n, lb, ub)) return NLOPT_INVALID_ARGS; return cdirect_unscaled(ni, f, f_data, lb, ub, x, minf, &stop, 0.0, (algorithm != NLOPT_GN_DIRECT) + 3 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 2 : (algorithm != NLOPT_GN_DIRECT)) + 9 * (algorithm == NLOPT_GN_DIRECT_L_RAND ? 1 : (algorithm != NLOPT_GN_DIRECT))); case NLOPT_GN_ORIG_DIRECT: case NLOPT_GN_ORIG_DIRECT_L: { direct_return_code dret; if (!finite_domain(n, lb, ub)) return NLOPT_INVALID_ARGS; opt->work = malloc(sizeof(double) * nlopt_max_constraint_dim(opt->m, opt->fc)); if (!opt->work) return NLOPT_OUT_OF_MEMORY; dret = direct_optimize(f_direct, opt, ni, lb, ub, x, minf, stop.maxeval, -1, stop.start, stop.maxtime, 0.0, 0.0, pow(stop.xtol_rel, (double) n), -1.0, stop.force_stop, stop.minf_max, 0.0, NULL, algorithm == NLOPT_GN_ORIG_DIRECT ? DIRECT_ORIGINAL : DIRECT_GABLONSKY); free(opt->work); opt->work = NULL; switch (dret) { case DIRECT_INVALID_BOUNDS: case DIRECT_MAXFEVAL_TOOBIG: case DIRECT_INVALID_ARGS: return NLOPT_INVALID_ARGS; case DIRECT_INIT_FAILED: case DIRECT_SAMPLEPOINTS_FAILED: case DIRECT_SAMPLE_FAILED: return NLOPT_FAILURE; case DIRECT_MAXFEVAL_EXCEEDED: case DIRECT_MAXITER_EXCEEDED: return NLOPT_MAXEVAL_REACHED; case DIRECT_MAXTIME_EXCEEDED: return NLOPT_MAXTIME_REACHED; case DIRECT_GLOBAL_FOUND: return NLOPT_MINF_MAX_REACHED; case DIRECT_VOLTOL: case DIRECT_SIGMATOL: return NLOPT_XTOL_REACHED; case DIRECT_OUT_OF_MEMORY: return NLOPT_OUT_OF_MEMORY; case DIRECT_FORCED_STOP: return NLOPT_FORCED_STOP; } break; } case NLOPT_GD_STOGO: case NLOPT_GD_STOGO_RAND: #ifdef WITH_CXX if (!finite_domain(n, lb, ub)) return NLOPT_INVALID_ARGS; if (!stogo_minimize(ni, f, f_data, x, minf, lb, ub, &stop, algorithm == NLOPT_GD_STOGO ? 0 : (int) POP(2*n))) return NLOPT_FAILURE; break; #else return NLOPT_INVALID_ARGS; #endif #if 0 /* lacking a free/open-source license, we no longer use Rowan's code, and instead use by "sbplx" re-implementation */ case NLOPT_LN_SUBPLEX: { int iret, freedx = 0; if (!opt->dx) { freedx = 1; if (nlopt_set_default_initial_step(opt, x) != NLOPT_SUCCESS) return NLOPT_OUT_OF_MEMORY; } iret = nlopt_subplex(f_bound, minf, x, n, opt, &stop, opt->dx); if (freedx) { free(opt->dx); opt->dx = NULL; } switch (iret) { case -2: return NLOPT_INVALID_ARGS; case -20: return NLOPT_FORCED_STOP; case -10: return NLOPT_MAXTIME_REACHED; case -1: return NLOPT_MAXEVAL_REACHED; case 0: return NLOPT_XTOL_REACHED; case 1: return NLOPT_SUCCESS; case 2: return NLOPT_MINF_MAX_REACHED; case 20: return NLOPT_FTOL_REACHED; case -200: return NLOPT_OUT_OF_MEMORY; default: return NLOPT_FAILURE; /* unknown return code */ } break; } #endif case NLOPT_LN_PRAXIS: { double step; if (initial_step(opt, x, &step) != NLOPT_SUCCESS) return NLOPT_OUT_OF_MEMORY; return praxis_(0.0, DBL_EPSILON, step, ni, x, f_bound, opt, &stop, minf); } case NLOPT_LD_LBFGS: return luksan_plis(ni, f, f_data, lb, ub, x, minf, &stop, opt->vector_storage); case NLOPT_LD_VAR1: case NLOPT_LD_VAR2: return luksan_plip(ni, f, f_data, lb, ub, x, minf, &stop, opt->vector_storage, algorithm == NLOPT_LD_VAR1 ? 1 : 2); case NLOPT_LD_TNEWTON: case NLOPT_LD_TNEWTON_RESTART: case NLOPT_LD_TNEWTON_PRECOND: case NLOPT_LD_TNEWTON_PRECOND_RESTART: return luksan_pnet(ni, f, f_data, lb, ub, x, minf, &stop, opt->vector_storage, 1 + (algorithm - NLOPT_LD_TNEWTON) % 2, 1 + (algorithm - NLOPT_LD_TNEWTON) / 2); case NLOPT_GN_CRS2_LM: if (!finite_domain(n, lb, ub)) return NLOPT_INVALID_ARGS; return crs_minimize(ni, f, f_data, lb, ub, x, minf, &stop, (int) POP(0), 0); case NLOPT_G_MLSL: case NLOPT_G_MLSL_LDS: case NLOPT_GN_MLSL: case NLOPT_GD_MLSL: case NLOPT_GN_MLSL_LDS: case NLOPT_GD_MLSL_LDS: { nlopt_opt local_opt = opt->local_opt; nlopt_result ret; if (!finite_domain(n, lb, ub)) return NLOPT_INVALID_ARGS; if (!local_opt && (algorithm == NLOPT_G_MLSL || algorithm == NLOPT_G_MLSL_LDS)) return NLOPT_INVALID_ARGS; if (!local_opt) { /* default */ nlopt_algorithm local_alg = (algorithm == NLOPT_GN_MLSL || algorithm == NLOPT_GN_MLSL_LDS) ? nlopt_local_search_alg_nonderiv : nlopt_local_search_alg_deriv; /* don't call MLSL recursively! */ if (local_alg >= NLOPT_GN_MLSL && local_alg <= NLOPT_GD_MLSL_LDS) local_alg = (algorithm == NLOPT_GN_MLSL || algorithm == NLOPT_GN_MLSL_LDS) ? NLOPT_LN_COBYLA : NLOPT_LD_MMA; local_opt = nlopt_create(local_alg, n); if (!local_opt) return NLOPT_FAILURE; nlopt_set_ftol_rel(local_opt, opt->ftol_rel); nlopt_set_ftol_abs(local_opt, opt->ftol_abs); nlopt_set_xtol_rel(local_opt, opt->xtol_rel); nlopt_set_xtol_abs(local_opt, opt->xtol_abs); nlopt_set_maxeval(local_opt, nlopt_local_search_maxeval); } if (opt->dx) nlopt_set_initial_step(local_opt, opt->dx); for (i = 0; i < n && stop.xtol_abs[i] > 0; ++i) ; if (local_opt->ftol_rel <= 0 && local_opt->ftol_abs <= 0 && local_opt->xtol_rel <= 0 && i < n) { /* it is not sensible to call MLSL without *some* nonzero tolerance for the local search */ nlopt_set_ftol_rel(local_opt, 1e-15); nlopt_set_xtol_rel(local_opt, 1e-7); } opt->force_stop_child = local_opt; ret = mlsl_minimize(ni, f, f_data, lb, ub, x, minf, &stop, local_opt, (int) POP(0), algorithm >= NLOPT_GN_MLSL_LDS && algorithm != NLOPT_G_MLSL); opt->force_stop_child = NULL; if (!opt->local_opt) nlopt_destroy(local_opt); return ret; } case NLOPT_LD_MMA: case NLOPT_LD_CCSAQ: { nlopt_opt dual_opt; nlopt_result ret; #define LO(param, def) (opt->local_opt ? opt->local_opt->param : (def)) dual_opt = nlopt_create(LO(algorithm, nlopt_local_search_alg_deriv), nlopt_count_constraints(opt->m, opt->fc)); if (!dual_opt) return NLOPT_FAILURE; nlopt_set_ftol_rel(dual_opt, LO(ftol_rel, 1e-14)); nlopt_set_ftol_abs(dual_opt, LO(ftol_abs, 0.0)); nlopt_set_maxeval(dual_opt, LO(maxeval, 100000)); #undef LO if (algorithm == NLOPT_LD_MMA) ret = mma_minimize(n, f, f_data, opt->m, opt->fc, lb, ub, x, minf, &stop, dual_opt); else ret = ccsa_quadratic_minimize( n, f, f_data, opt->m, opt->fc, opt->pre, lb, ub, x, minf, &stop, dual_opt); nlopt_destroy(dual_opt); return ret; } case NLOPT_LN_COBYLA: { nlopt_result ret; int freedx = 0; if (!opt->dx) { freedx = 1; if (nlopt_set_default_initial_step(opt, x) != NLOPT_SUCCESS) return NLOPT_OUT_OF_MEMORY; } return cobyla_minimize(n, f, f_data, opt->m, opt->fc, opt->p, opt->h, lb, ub, x, minf, &stop, opt->dx); if (freedx) { free(opt->dx); opt->dx = NULL; } return ret; } case NLOPT_LN_NEWUOA: { double step; if (initial_step(opt, x, &step) != NLOPT_SUCCESS) return NLOPT_OUT_OF_MEMORY; return newuoa(ni, 2*n+1, x, 0, 0, step, &stop, minf, f_noderiv, opt); } case NLOPT_LN_NEWUOA_BOUND: { double step; if (initial_step(opt, x, &step) != NLOPT_SUCCESS) return NLOPT_OUT_OF_MEMORY; return newuoa(ni, 2*n+1, x, lb, ub, step, &stop, minf, f_noderiv, opt); } case NLOPT_LN_BOBYQA: { nlopt_result ret; int freedx = 0; if (!opt->dx) { freedx = 1; if (nlopt_set_default_initial_step(opt, x) != NLOPT_SUCCESS) return NLOPT_OUT_OF_MEMORY; } ret = bobyqa(ni, 2*n+1, x, lb, ub, opt->dx, &stop, minf, opt->f, opt->f_data); if (freedx) { free(opt->dx); opt->dx = NULL; } return ret; } case NLOPT_LN_NELDERMEAD: case NLOPT_LN_SBPLX: { nlopt_result ret; int freedx = 0; if (!opt->dx) { freedx = 1; if (nlopt_set_default_initial_step(opt, x) != NLOPT_SUCCESS) return NLOPT_OUT_OF_MEMORY; } if (algorithm == NLOPT_LN_NELDERMEAD) ret= nldrmd_minimize(ni,f,f_data,lb,ub,x,minf,opt->dx,&stop); else ret= sbplx_minimize(ni,f,f_data,lb,ub,x,minf,opt->dx,&stop); if (freedx) { free(opt->dx); opt->dx = NULL; } return ret; } case NLOPT_AUGLAG: case NLOPT_AUGLAG_EQ: case NLOPT_LN_AUGLAG: case NLOPT_LN_AUGLAG_EQ: case NLOPT_LD_AUGLAG: case NLOPT_LD_AUGLAG_EQ: { nlopt_opt local_opt = opt->local_opt; nlopt_result ret; if ((algorithm == NLOPT_AUGLAG || algorithm == NLOPT_AUGLAG_EQ) && !local_opt) return NLOPT_INVALID_ARGS; if (!local_opt) { /* default */ local_opt = nlopt_create( algorithm == NLOPT_LN_AUGLAG || algorithm == NLOPT_LN_AUGLAG_EQ ? nlopt_local_search_alg_nonderiv : nlopt_local_search_alg_deriv, n); if (!local_opt) return NLOPT_FAILURE; nlopt_set_ftol_rel(local_opt, opt->ftol_rel); nlopt_set_ftol_abs(local_opt, opt->ftol_abs); nlopt_set_xtol_rel(local_opt, opt->xtol_rel); nlopt_set_xtol_abs(local_opt, opt->xtol_abs); nlopt_set_maxeval(local_opt, nlopt_local_search_maxeval); } if (opt->dx) nlopt_set_initial_step(local_opt, opt->dx); opt->force_stop_child = local_opt; ret = auglag_minimize(ni, f, f_data, opt->m, opt->fc, opt->p, opt->h, lb, ub, x, minf, &stop, local_opt, algorithm == NLOPT_AUGLAG_EQ || algorithm == NLOPT_LN_AUGLAG_EQ || algorithm == NLOPT_LD_AUGLAG_EQ); opt->force_stop_child = NULL; if (!opt->local_opt) nlopt_destroy(local_opt); return ret; } case NLOPT_GN_ISRES: if (!finite_domain(n, lb, ub)) return NLOPT_INVALID_ARGS; return isres_minimize(ni, f, f_data, (int) (opt->m), opt->fc, (int) (opt->p), opt->h, lb, ub, x, minf, &stop, (int) POP(0)); // case NLOPT_GN_ESCH: // if (!finite_domain(n, lb, ub)) return NLOPT_INVALID_ARGS; // return chevolutionarystrategy(n, f, f_data, // lb, ub, x, minf, &stop, // (unsigned) POP(0), // (unsigned) (POP(0)*1.5)); case NLOPT_LD_SLSQP: return nlopt_slsqp(n, f, f_data, opt->m, opt->fc, opt->p, opt->h, lb, ub, x, minf, &stop); default: return NLOPT_INVALID_ARGS; } return NLOPT_SUCCESS; /* never reached */ }