void Options::loadMultipliers (int n, int m, const mxArray* ptr, double*& zl, double*& zu, double*& lambda) { const mxArray* p; // Load the Lagrange multipliers associated with the lower bounds. p = mxGetField(ptr,0,"zl"); if (p) { if (!mxIsDouble(p) || (int) mxGetNumberOfElements(p) != n) throw MatlabException("The initial point for the Lagrange multipliers associated with the lower bounds must be a double-precision array with one element for each optimization variable"); zl = mxGetPr(p); } else zl = 0; // Load the Lagrange multipliers associated with the upper bounds. p = mxGetField(ptr,0,"zu"); if (p) { if (!mxIsDouble(p) || (int) mxGetNumberOfElements(p) != n) throw MatlabException("The initial point for the Lagrange multipliers associated with the upper bounds must be a double-precision array with one element for each optimization variable"); zu = mxGetPr(p); } else zu = 0; // Load the Lagrange multipliers associated with the equality and // inequality constraints. p = mxGetField(ptr,0,"lambda"); if (p) { if (m>0 && (!mxIsDouble(p) || (int) mxGetNumberOfElements(p) != m) ) throw MatlabException("The initial point for the Lagrange multipliers associated with the constraints must be a double-precision array with one element for each constraint"); lambda = mxGetPr(p); } else lambda = 0; }
//Vertical Concatentation of two sparse matrices into a new matrix void SparseMatrix::VertConcatenate(const SparseMatrix *obj, SparseMatrix *SpCat) { size_t ind = 0, i = 0, j = 0, k = 0; //Check dims if(this->w != obj->w) throw MatlabException("To vertically concatenate sparse matrices both must have the same number of columns"); //Save Sizes int N = this->w; int M1 = this->h; int M2 = obj->h; //Check sizes if(height(*SpCat) != M1+M2) throw MatlabException("Wrong number of rows in resulting matrix after concatenation"); if(width(*SpCat) != N) throw MatlabException("Wrong number of columns in resulting matrix after concatenation"); if(SpCat->numelems() != this->numelems()+obj->numelems()) throw MatlabException("Wrong number of nnzs in resulting matrix after concatenation"); //Concatenate into new matrix SpCat->jc[0] = 0; for(i = 1; i <= (size_t)N; i++) { SpCat->jc[i] = this->jc[i] + obj->jc[i]; for(j = 0; j < this->jc[i]-this->jc[i-1]; j++) { ind = this->jc[i-1]+j; SpCat->ir[k] = this->ir[ind]; SpCat->x[k++] = this->x[ind]; } for(j = 0; j < obj->jc[i]-obj->jc[i-1]; j++) { ind = obj->jc[i-1]+j; SpCat->ir[k] = obj->ir[ind]+M1; SpCat->x[k++] = obj->x[ind]; } } }
TNLP::LinearityType* Options::loadVariableLinearity(int n, const mxArray *ptr) { TNLP::LinearityType* varlin = new TNLP::LinearityType[n]; //The return value const mxArray* p = mxGetField(ptr,0,"var_lin"); double* types; if(p) { if (!mxIsDouble(p) || (mxGetNumberOfElements(p) != n)) throw MatlabException("The var_lin array must be a double-precision array with n elements"); //Get The Variable Types types = mxGetPr(p); //Assign them to TMINLP types for(int i = 0; i < n; i++) { switch((int)types[i]) { case 0: varlin[i] = TNLP::NON_LINEAR; break; case 1: varlin[i] = TNLP::LINEAR; break; default: throw MatlabException("The var_lin array must only contain 0 (nonlinear), or 1 (linear)!"); break; } } } else { for(int i = 0; i < n; i++) varlin[i] = TNLP::NON_LINEAR; //assume all nonlinear } return varlin; }
// Function definitions. // ----------------------------------------------------------------- double* getMatlabMatrixDouble (const mxArray* ptr) { if (mxGetNumberOfDimensions(ptr) != 2) throw MatlabException("Matlab array must be a matrix"); if (!mxIsDouble(ptr)) throw MatlabException("Matlab array must be of type double"); return mxGetPr(ptr); }
void MatlabJournal::PrintfImpl (EJournalCategory category, EJournalLevel level, const char* pformat, va_list ap) { const int maxStrLen = 1024; char s[maxStrLen]; #ifdef HAVE_VSNPRINTF # ifdef HAVE_VA_COPY va_list apcopy; va_copy(apcopy, ap); if (vsnprintf(s,maxStrLen,pformat,apcopy) >= maxStrLen) throw MatlabException("String buffer it too short for all the characters to be printed to MATLAB console"); va_end(apcopy); # else if (vsnprintf(s,maxStrLen,pformat,ap) >= maxStrLen) throw MatlabException("String buffer it too short for all the characters to be printed to MATLAB console"); # endif #else # ifdef HAVE__VSNPRINTF # ifdef HAVE_VA_COPY va_list apcopy; va_copy(apcopy, ap); if (_vsnprintf(s,maxStrLen,pformat,apcopy) >= maxStrLen) throw MatlabException("String buffer it too short for all the characters to be printed to MATLAB console"); va_end(apcopy); # else if (_vsnprintf(s,maxStrLen,pformat,ap) >= maxStrLen) throw MatlabException("String buffer it too short for all the characters to be printed to MATLAB console"); # endif # else vsprintf(s,pformat,ap); # endif #endif mexPrintf(s); mexEvalString("drawnow;"); //flush draw buffer }
// Function definitions for class MatlabString. // ----------------------------------------------------------------- MatlabString::MatlabString (const mxArray* ptr) { s = 0; // Check to make sure the Matlab array is a string. if (!mxIsChar(ptr)) throw MatlabException("Matlab array must be a string (of type CHAR)"); // Get the string passed as a Matlab array. s = mxArrayToString(ptr); if (s == 0) throw MatlabException("Unable to obtain string from Matlab array"); }
// Function definitions for clas Multipliers. // ----------------------------------------------------------------- Multipliers::Multipliers (const mxArray*& ptr) { mxArray* p; // First check to see whether the MATLAB array is a structure // array. If not, throw an exception. if (!mxIsStruct(ptr)) throw MatlabException("Matlab array must be a structure array"); // Get the multipliers corresponding to the lower bounds on the // optimization variables. p = mxGetField(ptr,0,lowerBoundMultipliersLabel); if (p == 0) throw MatlabException("MATLAB multipliers input does not have the \ correct fields"); zl = new Matrix(p); // Get the multipliers corresponding to the upper bounds on the // optimization variables. p = mxGetField(ptr,0,upperBoundMultipliersLabel); if (p == 0) throw MatlabException("MATLAB multipliers input does not have the \ correct fields"); zu = new Matrix(p); // Get the multipliers corresponding to the upper bounds on the // optimization variables. p = mxGetField(ptr,0,constraintMultipliersLabel); if (p == 0) throw MatlabException("MATLAB multipliers input does not have the \ correct fields"); lambda = new Matrix(p); }
double* Options::loadUpperBounds(int n, const mxArray* ptr, double posinfty) { double* ub; // The return value. // Load the upper bounds on the variables. const mxArray* p = mxGetField(ptr,0,"ub"); if (p) { // Load the upper bounds and check to make sure they are valid. int N = Iterate::getMatlabData(p,ub); if (N != n) throw MatlabException("Upper bounds array must have one element for each optimization variable"); // Convert MATLAB's convention of infinity to BONMIN's convention // of infinity. for (int i = 0; i < n; i++) if (mxIsInf(ub[i])) ub[i] = posinfty; } else { // If the upper bounds have not been specified, set them to // positive infinity. ub = new double[n]; for (int i = 0; i < n; i++) ub[i] = posinfty; } return ub; }
TNLP::LinearityType* Options::loadConstraintLinearity(int m, int nlin, int nnlin, const mxArray *ptr) { TNLP::LinearityType* conslin = new TNLP::LinearityType[m]; //The return value const mxArray* p = mxGetField(ptr,0,"cons_lin"); double* types; if(m != (nlin+nnlin)) throw MatlabException("The total number of constraints does not equal #lin + #nlin"); if(p) { if (!mxIsDouble(p) || (mxGetNumberOfElements(p) != m)) throw MatlabException("The cons_lin array must be a double-precision array with m elements"); //Get The Variable Types types = mxGetPr(p); //Assign them to TMINLP types for(int i = 0; i < m; i++) { //Let the user decide for callback constraints what is nonlinear and linear if(i < nnlin) { switch((int)types[i]) { case 0: conslin[i] = TNLP::NON_LINEAR; break; case 1: conslin[i] = TNLP::LINEAR; break; default: throw MatlabException("The cons_lin array must only contain 0 (nonlinear), or 1 (linear)!"); break; } } else conslin[i] = TNLP::LINEAR; //force linear constraints (via A) to be identified as linear } } else { //Fill in based on nlin and nnlin (noting nonlinear constraints come first based on our concatenation) for(int i = 0; i < nnlin; i++) conslin[i] = TNLP::NON_LINEAR; for(int i = nnlin; i < (nnlin + nlin); i++) conslin[i] = TNLP::LINEAR; } return conslin; }
TMINLP::VariableType* Options::loadVariableTypes(int n, const mxArray *ptr) { TMINLP::VariableType* vartype = new TMINLP::VariableType[n]; //The return value const mxArray* p = mxGetField(ptr,0,"var_type"); double* types; if(p) { if (!mxIsDouble(p) || (mxGetNumberOfElements(p) != n)) throw MatlabException("The var_type array must be a double-precision array with n elements"); //Get The Variable Types types = mxGetPr(p); //Assign them to TMINLP types for(int i = 0; i < n; i++) { switch((int)types[i]) { case -1: vartype[i] = TMINLP::BINARY; //doesn't seem to work? break; case 0: vartype[i] = TMINLP::CONTINUOUS; break; case 1: vartype[i] = TMINLP::INTEGER; break; default: throw MatlabException("The var_type array must only contain -1 (binary), 0 (continous) or 1 (integer)!"); break; } } } else { for(int i = 0; i < n; i++) vartype[i] = TMINLP::CONTINUOUS; //assume all continuous } return vartype; }
// Function definitions for class Iterate. // ----------------------------------------------------------------- Iterate::Iterate (mxArray* ptr) : nv(0), ptr(ptr) { const mxArray* p = 0; // Pointer to a MATLAB array. // Compute the number of optimization variables. if (mxIsCell(ptr)) { // The MATLAB array is a cell array. Repeat for each cell. int n = mxGetNumberOfElements(ptr); for (int i = 0; i < n; i++) { p = mxGetCell(ptr,i); // Get the ith cell. if (!mxIsDouble(p) || mxIsComplex(ptr) || mxIsSparse(ptr)) throw MatlabException("The initial iterate must be either a REAL DENSE array in DOUBLE precision, or a cell array in which each cell is a REAL DENSE array in DOUBLE precision"); nv += mxGetNumberOfElements(p); } } else { // The MATLAB array should be a numeric array. if (!mxIsDouble(ptr) || mxIsComplex(ptr) || mxIsSparse(ptr)) throw MatlabException("The initial iterate must be either a REAL DENSE array in DOUBLE precision, or a cell array in which each cell is a REAL DENSE array in DOUBLE precision"); nv = mxGetNumberOfElements(ptr); } }
//Sparse Matrix*Vector using MATLAB (assumes constant structure as per linear A) void SparseMatrix::SpMatrixVec(const Iterate& xin, double *c) { //Sizes int M = this->h; int N = this->w; //Check dims if(w != numvars(xin)) throw MatlabException("To multiply a sparse matrix by a vector the number of columns in the matrix must equal the number of rows in the vector"); if(linA == NULL) throw MatlabException("Error with sparse matrix linear A memory"); //Check if existing vec_c memory exists, if not, create it and assign pointers at the same time if(vec_c == NULL) { prhs[0] = this->linA; prhs[1] = mxCreateDoubleMatrix(N,1,mxREAL); vec_c = mxCreateDoubleMatrix(M,1,mxREAL); } //Copy in current x iterate to MATLAB memory xin.copyto(mxGetPr(prhs[1])); //Call Matlab to evaluate sparse Matrix * Vector try { mexCallMATLAB(1,&vec_c,2,prhs,"mtimes"); } catch (std::exception ME) { const char* what = ME.what(); if (what) { mexPrintf("Matlab exception:\n%s", what); throw MatlabException("There was an error when executing the linear constraints"); } } catch (...) { throw MatlabException("There was an error when executing the linear constraints"); } //Copy results to output c pointer memcpy(c,mxGetPr(vec_c),M*sizeof(double)); }
int Options::loadConstraintBounds (const mxArray* ptr, double*& cl, double*& cu, double neginfty, double posinfty, int &lin, int &nlin) { int m = 0; // The return value is the number of constraints. int tm; //Defaults lin = 0; nlin = 0; // LOAD CONSTRAINT BOUNDS. // If the user has specified constraints bounds, then she must // specify *both* the lower and upper bounds. const mxArray* pl = mxGetField(ptr,0,"cl"); const mxArray* pu = mxGetField(ptr,0,"cu"); const mxArray* prl = mxGetField(ptr,0,"rl"); //linear constraint bounds const mxArray* pru = mxGetField(ptr,0,"ru"); if (pl || pu || prl || pru) { // Check to make sure the constraint bounds are valid. if ((!pl ^ !pu) || (!prl ^ !pru)) throw MatlabException("You must specify both lower and upper bounds on the constraints"); if (pl && (!mxIsDouble(pl) || !mxIsDouble(pu) || (mxGetNumberOfElements(pl) != mxGetNumberOfElements(pu)))) throw MatlabException("The nonlinear constraints lower and upper bounds must both be double-precision arrays with the same number of elements"); if (prl && (!mxIsDouble(prl) || !mxIsDouble(pru) || (mxGetNumberOfElements(prl) != mxGetNumberOfElements(pru)))) throw MatlabException("The linear constraints lower and upper bounds must both be double-precision arrays with the same number of elements"); // Get the number of constraints. if(pl && prl) { lin = (int)mxGetNumberOfElements(prl); nlin = (int)mxGetNumberOfElements(pl); m = lin+nlin; } else if(pl) { lin = 0; nlin = (int)mxGetNumberOfElements(pl); m = nlin; } else { lin = (int)mxGetNumberOfElements(prl); nlin = 0; m = lin; } // Load the lower bounds on the constraints and convert MATLAB's // convention of infinity to IPOPT's convention of infinity. cl = new double[m]; cu = new double[m]; if(pl && prl) { tm = (int)mxGetNumberOfElements(pl); copymemory(mxGetPr(pl),cl,tm); copymemory(mxGetPr(pu),cu,tm); copymemory(mxGetPr(prl),&cl[tm],(int)mxGetNumberOfElements(prl)); copymemory(mxGetPr(pru),&cu[tm],(int)mxGetNumberOfElements(pru)); } else if(pl) { copymemory(mxGetPr(pl),cl,m); copymemory(mxGetPr(pu),cu,m); } else { copymemory(mxGetPr(prl),cl,m); copymemory(mxGetPr(pru),cu,m); } // Convert MATLAB's convention of infinity to IPOPT's convention // of infinity. for (int i = 0; i < m; i++) { if (mxIsInf(cl[i])) cl[i] = neginfty; if (mxIsInf(cu[i])) cu[i] = posinfty; } } return m; }
// Function definitions. // ----------------------------------------------------------------- void mexFunction (int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) try { // Check to see if we have the correct number of input and output // arguments. if (nrhs < minNumInputArgs) throw MatlabException("Incorrect number of input arguments"); // Get the starting point for the variables. This is specified in // the first input argument. The variables must be either a single // matrix or a cell array of matrices. int k = 0; // The index of the current input argument. ArrayOfMatrices x0(prhs[k++]); // Create the output, which stores the solution obtained from // running IPOPT. There should be as many output arguments as cell // entries in X. if (nlhs != x0.length()) throw MatlabException("Incorrect number of output arguments"); ArrayOfMatrices x(plhs,x0); // Load the lower and upper bounds on the variables as // ArrayOfMatrices objects. They should have the same structure as // the ArrayOfMatrices object "x". ArrayOfMatrices lb(prhs[k++]); ArrayOfMatrices ub(prhs[k++]); // Check to make sure the bounds make sense. if (lb != x || ub != x) throw MatlabException("Input arguments LB and UB must have the same \ structure as X"); // Get the Matlab callback functions. MatlabString objFunc(prhs[k++]); MatlabString gradFunc(prhs[k++]); // Get the auxiliary data. const mxArray* auxData; const mxArray* ptr = prhs[k++]; if (nrhs > 5) { if (mxIsEmpty(ptr)) auxData = 0; else auxData = ptr; } else auxData = 0; // Get the intermediate callback function. MatlabString* iterFunc; ptr = prhs[k++]; if (nrhs > 6) { if (mxIsEmpty(ptr)) iterFunc = 0; else iterFunc = new MatlabString(ptr); } else iterFunc = 0; // Set the options for the L-BFGS algorithm to their defaults. int maxiter = defaultmaxiter; int m = defaultm; double factr = defaultfactr; double pgtol = defaultpgtol; // Process the remaining input arguments, which set options for // the IPOPT algorithm. while (k < nrhs) { // Get the option label from the Matlab input argument. MatlabString optionLabel(prhs[k++]); if (k < nrhs) { // Get the option value from the Matlab input argument. MatlabScalar optionValue(prhs[k++]); double value = optionValue; if (!strcmp(optionLabel,"maxiter")) maxiter = (int) value; else if (!strcmp(optionLabel,"m")) m = (int) value; else if (!strcmp(optionLabel,"factr")) factr = value / mxGetEps(); else if (!strcmp(optionLabel,"pgtol")) pgtol = value; else { if (iterFunc) delete iterFunc; throw MatlabException("Nonexistent option"); } } } // Create a new instance of the optimization problem. x = x0; MatlabProgram program(x,lb,ub,&objFunc,&gradFunc,iterFunc, (mxArray*) auxData,m,maxiter,factr,pgtol); // Run the L-BFGS-B solver. SolverExitStatus exitStatus = program.runSolver(); if (exitStatus == abnormalTermination) { if (iterFunc) delete iterFunc; throw MatlabException("Solver unable to satisfy convergence \ criteria due to abnormal termination"); } else if (exitStatus == errorOnInput) {