// Main Entry Function // ----------------------------------------------------------------- void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { //Input Args usrFcn fun, con; double *x0, *lb = NULL, *ub = NULL; char *xtype = NULL; //Outputs Args double *x, *fval, *exitflag, *iter, *nfval; //Internal Vars size_t ndec; int i, nobj = 1, ncon = 0; char errstr[1024]; //used for returning error info iter_fun_data iterF; //Check user inputs if(!checkInputs(prhs,nrhs,plhs,nlhs)) return; //Redirect cout printfbuf buf; std::streambuf *cout_sbuf = std::cout.rdbuf(); //keep existing buffer std::cout.rdbuf(&buf); //redirect buffer //NOMAD Vars NOMAD::Mads *mads; NOMAD::Display out(std::cout); NOMAD::Parameters p(out); NOMAD::Point px0; NOMAD::Double *nx0; NOMAD::stop_type stopflag; //Evaluator Vars matlabEval *mSEval = NULL; matlabMEval *mBEval = NULL; //Set Option Defaults int printLevel = 0; char *paramfile = NULL; mxArray *bb_out_type = NULL; iterF.enabled = false; //Get Size ndec = mxGetNumberOfElements(pX0); //Get Blackbox / Objective Function Handle if (mxIsChar(pFUN)) { if(mxGetString(pFUN, fun.f, FLEN) != 0) mexErrMsgTxt("error reading objective name string"); fun.nrhs = 1; fun.xrhs = 0; } else { fun.prhs[0] = (mxArray*)pFUN; strcpy(fun.f, "feval"); fun.nrhs = 2; fun.xrhs = 1; } fun.prhs[fun.xrhs] = mxCreateDoubleMatrix(ndec, 1, mxREAL); //x //Get x0 x0 = mxGetPr(pX0); //Get xtype if(nrhs > eXTYPE && !mxIsEmpty(pXTYPE)) xtype = mxArrayToString(pXTYPE); //Get MEX Options if specified if(nrhs > eOPTS && !mxIsEmpty(pOPTS)) { if(mxGetField(pOPTS,0,"display_degree") && !mxIsEmpty(mxGetField(pOPTS,0,"display_degree"))) printLevel = (int)*mxGetPr(mxGetField(pOPTS,0,"display_degree")); if(mxGetField(pOPTS,0,"param_file") && !mxIsEmpty(mxGetField(pOPTS,0,"param_file"))) paramfile = mxArrayToString(mxGetField(pOPTS,0,"param_file")); if(mxGetField(pOPTS,0,"bb_output_type") && !mxIsEmpty(mxGetField(pOPTS,0,"bb_output_type"))) bb_out_type = mxGetField(pOPTS,0,"bb_output_type"); if(mxGetField(pOPTS,0,"iterfun") && !mxIsEmpty(mxGetField(pOPTS,0,"iterfun"))) { iterF.prhs[0] = (mxArray*)mxGetField(pOPTS,0,"iterfun"); strcpy(iterF.f, "feval"); iterF.enabled = true; iterF.prhs[1] = mxCreateNumericMatrix(1,1,mxINT32_CLASS,mxREAL); iterF.prhs[2] = mxCreateDoubleMatrix(1,1,mxREAL); iterF.prhs[3] = mxCreateDoubleMatrix(ndec,1,mxREAL); } } //Create Outputs (note x and fval created below, due to allowing bi-objective) plhs[2] = mxCreateDoubleMatrix(1,1, mxREAL); plhs[3] = mxCreateDoubleMatrix(1,1, mxREAL); plhs[4] = mxCreateDoubleMatrix(1,1, mxREAL); exitflag = mxGetPr(plhs[2]); iter = mxGetPr(plhs[3]); nfval = mxGetPr(plhs[4]); //Setup ndec p.set_DIMENSION((int)ndec); //Warn if >1000 if(ndec > 1000 && printLevel) { sprintf(errstr,"Warning: NOMAD is designed problems less than 1000 variables. Your model has %d.\nWhile unlikely, it is possible NOMAD may not perform as intended on this problem.",static_cast<int>(ndec)); mexWarnMsgTxt(errstr); } //Setup Lower Bounds if(nrhs > eLB && !mxIsEmpty(pLB)) { NOMAD::Point ptLB; NOMAD::Double *dLB = new NOMAD::Double[ndec]; lb = mxGetPr(pLB); for(i=0;i<ndec;i++) { if(!mxIsInf(lb[i])) //if not initialized will not be used dLB[i] = lb[i]; } ptLB.set((int)ndec,dLB); p.set_LOWER_BOUND(ptLB); delete [] dLB; } //Setup Upper Bounds if(nrhs > eUB && !mxIsEmpty(pUB)) { NOMAD::Point ptUB; NOMAD::Double *dUB = new NOMAD::Double[ndec]; ub = mxGetPr(pUB); for(i=0;i<ndec;i++) { if(!mxIsInf(ub[i])) //if not initialized will not be used dUB[i] = ub[i]; } ptUB.set((int)ndec,dUB); p.set_UPPER_BOUND(ptUB); delete [] dUB; } //Setup x0 nx0 = new NOMAD::Double[ndec]; #ifdef OPTI_VERSION double xl, xu; //If integer variables declared, need to ensure x0[i] is an integer if(xtype) { for(i=0;i<ndec;i++) { switch(tolower(xtype[i])) { case 'c': //Ensure within bounds if(lb && x0[i] < lb[i]) nx0[i] = lb[i]; else if(ub && x0[i] > ub[i]) nx0[i] = ub[i]; else nx0[i] = x0[i]; //no rounding break; case 'i': case 'b': xl = floor(x0[i]); //First round is a floor //If lower bounds exist if(lb) { //if lower bound broken if(xl < lb[i]) { xu = ceil(x0[i]); //If upper bounds exist, check bound directions if(ub && xu > ub[i]) { //if broken, no integer x0 exists sprintf(errstr,"x0[%d] cannot be rounded to an integer value between lb: %g, ub %g",i,lb[i],ub[i]); mexErrMsgTxt(errstr); } if(xu != x0[i]) { //If we changed something, warn user sprintf(errstr,"x0[%d] was rounded up to %g to suit NOMAD interface",i,xu); mexWarnMsgTxt(errstr); } //Save ceil value nx0[i] = xu; } //Floor value did not break lower bounds, value OK else { if(xl != x0[i]) { //If we changed something, warn user sprintf(errstr,"x0[%d] was rounded down to %g to suit NOMAD interface",i,xl); mexWarnMsgTxt(errstr); } //Save floor value nx0[i] = xl; } } //No lower bounds, floor value assumed OK else { if(xl != x0[i]) { //If we changed something, warn user sprintf(errstr,"x0[%d] was rounded down to %g to suit NOMAD interface",i,xl); mexWarnMsgTxt(errstr); } //Save floor value nx0[i] = xl; } break; case 'r': mexErrMsgTxt("Please specify continuous (real) variables using 'c' (as opposed to 'r') when using the OPTI version"); break; default: sprintf(errstr,"Unknown xtype[%d] character: %c\n\nValid options are 'C', 'I', or 'B'\n",i,xtype[i]); mexErrMsgTxt(errstr); } } } //Else user start position within bounds else { for(i=0;i<ndec;i++) { if(lb && x0[i] < lb[i]) nx0[i] = lb[i]; else if(ub && x0[i] > ub[i]) nx0[i] = ub[i]; else nx0[i] = x0[i]; } } #else //GERAD VERSION - no x0 checking for(i=0;i<ndec;i++) nx0[i] = x0[i]; #endif px0.set((int)ndec,nx0); p.set_X0(px0); delete [] nx0; #ifdef OPTI_VERSION //Setup Nonlinear Constraints if(nrhs > eNLCON && !mxIsEmpty(pNLCON)) { if (mxIsChar(pNLCON)) { if(mxGetString(pNLCON, con.f, FLEN) != 0) mexErrMsgTxt("error reading constraint name string"); con.nrhs = 1; con.xrhs = 0; } else { con.prhs[0] = (mxArray*)pNLCON; strcpy(con.f, "feval"); con.nrhs = 2; con.xrhs = 1; } con.prhs[con.xrhs] = mxCreateDoubleMatrix(ndec, 1, mxREAL); //x if(nrhs < eNLRHS+1 || mxIsEmpty(pNLRHS)) {//we will default to <= 0 ncon = -1; con.nlrhs = NULL; } else { ncon = (int)mxGetNumberOfElements(pNLRHS); con.nlrhs = mxGetPr(pNLRHS); } } //Setup Input Variable Types if(xtype) p.set_BB_INPUT_TYPE(detInTypes(xtype,ndec)); //Setup Evaluation Return Types + #'s of Obj + Con p.set_BB_OUTPUT_TYPE(detRetTypes(&fun,bb_out_type,&nobj,&con,&ncon,x0,ndec)); //Set All Normal NOMAD Options p.set_DISPLAY_DEGREE(0); //default #endif //GERAD Version does not have a separate constraint handler and handles input and output types using options //Set User Options if(nrhs > eOPTS && !mxIsEmpty(pOPTS)) setNOMADopts(p,pOPTS); else setNOMADopts(p,NULL); //If the user has specified a parameter file to read, see if it exists, and if so, read and parse it. if(paramfile) { FILE *pFile = fopen(paramfile,"r"); if(pFile==NULL) { sprintf(errstr,"Cannot open parameter file: %s\n\nEnsure it exists!",paramfile); mexErrMsgTxt(errstr); } else{ fclose(pFile); //close file pointer (we don't need it) try { p.read(paramfile); } catch(exception &e) { sprintf(errstr,"NOMAD Parameter File Read Error:\n\n%s",e.what()); mexErrMsgTxt(errstr); } } } //Check NOMAD parameters try { p.check(); } catch(exception &e) { sprintf(errstr,"NOMAD Parameter Error:\n\n%s",e.what()); mexErrMsgTxt(errstr); } //Check for categorical variables if (p.get_signature()->has_categorical()) mexErrMsgTxt("The MATLAB version of NOMAD does not support categorical variables yet! Check BB_INPUT_TYPE parameter."); //If GERAD version, obtain number of objectives and constraints from parameters #ifndef OPTI_VERSION nobj=p.get_nb_obj(); ncon=(int)p.get_bb_output_type().size()-nobj; #endif //If user has requested surrogates, setup extra input arg to callbacks if (p.has_sgte()) { fun.prhs[fun.xrhs+1] = mxCreateLogicalMatrix(1,1); //extra logical indicating surrogate or not fun.nrhs++; #ifdef OPTI_VERSION con.prhs[con.xrhs+1] = mxCreateLogicalMatrix(1,1); con.nrhs++; #endif } //Print Header if(printLevel) { mexPrintf("\n------------------------------------------------------------------\n"); mexPrintf(" This is NOMAD v%s\n",NOMAD::VERSION.c_str()); mexPrintf(" Authors: M. Abramson, C. Audet, G. Couture, J. Dennis, S. Le Digabel, C. Tribes\n\n"); mexPrintf(" Problem Properties:\n"); mexPrintf(" # Decision Variables: %4d\n",ndec); mexPrintf(" # Number of Objectives: %4d\n",nobj); mexPrintf(" # Number of Nonlinear Constraints: %4d\n",ncon); mexPrintf("------------------------------------------------------------------\n"); mexEvalString("drawnow;"); //flush draw buffer } //Let this file sort out errors mexSetTrapFlag(1); //Reset tags and bbe (C.Tribes 3/14) NOMAD::Eval_Point::reset_tags_and_bbes(); //Create evaluator and run mads based on number of objectives try { if(nobj > 1) { mBEval = new matlabMEval(p,&fun,nobj,&con,ncon,&iterF); //Bi-Objective Evaluator mads = new NOMAD::Mads(p, mBEval); //Run NOMAD stopflag = mads->multi_run(); } else { mSEval = new matlabEval(p,&fun,nobj,&con,ncon,&iterF); //Single Objective Evaluator mads = new NOMAD::Mads(p, mSEval); //Run NOMAD stopflag = mads->run(); } } catch(exception &e) { //Free Memory (C.Tribes 3/14) if(mSEval) delete mSEval; mSEval = NULL; if(mBEval) delete mBEval; mBEval = NULL; delete mads; if(xtype) mxFree(xtype); xtype = NULL; //Report Error sprintf(errstr,"NOMAD Run Error:\n\n%s",e.what()); mexErrMsgTxt(errstr); } if(printLevel) mexPrintf("------------------------------------------------------------------\n"); //Obtain Solution based on Single or Multi-Objective (C.Tribes oct 09, 2013 --- changed to deal with pareto output) if(nobj>1) { NOMAD::Pareto_Front * pareto_front=mads->get_pareto_front(); if (pareto_front) { int nb_pareto_pts = pareto_front->size(); plhs[0] = mxCreateDoubleMatrix(ndec,nb_pareto_pts, mxREAL); plhs[1] = mxCreateDoubleMatrix(nobj,nb_pareto_pts, mxREAL); x = mxGetPr(plhs[0]); fval = mxGetPr(plhs[1]); const NOMAD::Eval_Point * cur = pareto_front->begin(); int i=0; while ( cur ) { //mexPrintf("i %d OK: %d FEAS: %d\n",i,cur->is_eval_ok(),cur->is_feasible ( p.get_h_min() )); if ( cur->is_eval_ok() && cur->is_feasible ( p.get_h_min() ) ) { const std::list<int> & index_obj = p.get_index_obj(); std::list<int>::const_iterator it , end = index_obj.end(); const NOMAD::Point & bbo = cur->get_bb_outputs(); int j = 0; NOMAD::Point multi_obj ( static_cast<int>(index_obj.size()) ); for ( it = index_obj.begin() ; it != end ; ++it,j++ ) fval[nobj*i+j] = bbo[*it].value(); for(j=0;j<ndec;j++) x[ndec*i+j] = (*cur)[j].value(); } cur = pareto_front->next(); i++; } *exitflag = getStatus(stopflag); } else { stopflag = (NOMAD::stop_type)10; *exitflag = -1; //No solution } } else { //Create single objective outputs plhs[0] = mxCreateDoubleMatrix(ndec,1, mxREAL); plhs[1] = mxCreateDoubleMatrix(1,1, mxREAL); x = mxGetPr(plhs[0]); fval = mxGetPr(plhs[1]); const NOMAD::Eval_Point *bestSol = mads->get_best_feasible(); if(bestSol == NULL) { bestSol = mads->get_best_infeasible(); //manually set as infeasible (no infeasible stop flag) stopflag = (NOMAD::stop_type)10; } if(bestSol == NULL) *exitflag = -1; //No solution //If we have a solution, save it if(*exitflag != -1) { //Save x NOMAD::Point pt(*bestSol); for(i=0;i<ndec;i++) x[i] = pt[i].value(); //Save fval *fval = bestSol->get_f().value(); //Save Status *exitflag = getStatus(stopflag); } } //Common outputs *iter = mads->get_stats().get_iterations(); *nfval = mads->get_stats().get_bb_eval(); //Return cout to initial buffer std::cout.rdbuf(cout_sbuf); //Return error control to default mexSetTrapFlag(0); //Free Memory if(mSEval) delete mSEval; mSEval = NULL; if(mBEval) delete mBEval; mBEval = NULL; delete mads; if(xtype) mxFree(xtype); xtype = NULL; }
/*------------------------------------------*/ int main ( int argc , char ** argv ) { // display: NOMAD::Display out ( NOMAD::rout ); //zhenghua out.precision ( NOMAD::DISPLAY_PRECISION_STD ); std::string error; { // NOMAD initializations: NOMAD::begin ( argc , argv ); // usage: if ( argc < 2 ) { NOMAD::display_usage ( out); //zhenghua NOMAD::end(); return EXIT_FAILURE; } // parameters file: std::string param_file_name = argv[1]; std::string opt = param_file_name; NOMAD::toupper ( opt ); // display version if option '-v' has been specified: if ( opt == "-U" ) { NOMAD::display_usage ( out ); NOMAD::end(); return EXIT_SUCCESS; } // display version if option '-v' has been specified: if ( opt == "-V" || opt =="-VERSION") { NOMAD::display_version ( out ); NOMAD::end(); return EXIT_SUCCESS; } // display info if option '-i' has been specified: if ( opt == "-I" || opt == "-INFO" ) { NOMAD::display_info ( out ); NOMAD::display_usage ( out ); //zhenghua NOMAD::end(); return EXIT_SUCCESS; } // parameters creation: NOMAD::Parameters p ( out ); // display help on parameters if option '-h' has been specified: if ( opt == "-H" || opt == "-HELP" ) { p.help ( argc , argv ); NOMAD::end(); return EXIT_SUCCESS; } // display developer help on parameters if option '-d' has been specified: if ( opt == "-D" ) { p.help ( argc , argv,true ); NOMAD::end(); return EXIT_SUCCESS; } // check the number of processess: #ifdef USE_MPI if ( NOMAD::Slave::get_nb_processes() < 2 ) { NOMAD::rout << "ERROR: Incorrect command to run with MPI." << std::endl; //zhenghua NOMAD::display_usage ( out ); //zhenghua NOMAD::end(); return EXIT_FAILURE; } #endif try { // read parameters file: p.read ( param_file_name ); // parameters check: p.check(); // display NOMAD info: if ( p.get_display_degree() > NOMAD::MINIMAL_DISPLAY) NOMAD::display_info ( out ); // parameters display: if ( NOMAD::Slave::is_master() && p.get_display_degree() == NOMAD::FULL_DISPLAY ) out << std::endl << NOMAD::open_block ( "parameters" ) << std::endl << p << NOMAD::close_block(); // algorithm creation and execution: NOMAD::Mads mads ( p , NULL ); if ( p.get_nb_obj() == 1 ) mads.run(); else mads.multi_run(); #ifdef MODEL_STATS mads.display_model_stats ( out ); #endif } catch ( std::exception & e ) { if ( NOMAD::Slave::is_master() ) { error = std::string ( "NOMAD has been interrupted: " ) + e.what(); NOMAD::rout << std::endl << error << std::endl << std::endl; //zhenghua } } NOMAD::Slave::stop_slaves ( out ); NOMAD::end(); } #ifdef MEMORY_DEBUG NOMAD::display_cardinalities ( out ); #endif return ( error.empty() ) ? EXIT_SUCCESS : EXIT_FAILURE; }