1 // Copyright (C) 2008 Peter Carbonetto. All Rights Reserved.
2 // This code is published under the Eclipse Public License.
3 //
4 // Author: Peter Carbonetto
5 //         Dept. of Computer Science
6 //         University of British Columbia
7 //         September 18, 2008
8 
9 #include "mex.h"
10 #include "iterate.hpp"
11 #include "options.hpp"
12 #include "matlabexception.hpp"
13 #include "callbackfunctions.hpp"
14 #include "matlabinfo.hpp"
15 #include "matlabjournal.hpp"
16 #include "matlabprogram.hpp"
17 #include "IpRegOptions.hpp"
18 #include "IpJournalist.hpp"
19 #include "IpIpoptApplication.hpp"
20 #include "IpSolveStatistics.hpp"
21 
22 using Ipopt::IsValid;
23 using Ipopt::RegisteredOption;
24 using Ipopt::EJournalLevel;
25 using Ipopt::Journal;
26 using Ipopt::MatlabJournal;
27 using Ipopt::IpoptApplication;
28 using Ipopt::SmartPtr;
29 using Ipopt::TNLP;
30 using Ipopt::ApplicationReturnStatus;
31 using Ipopt::SolveStatistics;
32 
33 extern void _main();
34 
35 // Function definitions.
36 // -----------------------------------------------------------------
mexFunction(int nlhs,mxArray * plhs[],int nrhs,const mxArray * prhs[])37 void mexFunction (int nlhs, mxArray *plhs[],
38 		  int nrhs, const mxArray *prhs[])
39   try {
40 
41     // Check to see if we have the correct number of input and output
42     // arguments.
43     if (nrhs != 3)
44       throw MatlabException("Incorrect number of input arguments");
45     if (nlhs != 2)
46       throw MatlabException("Incorrect number of output arguments");
47 
48     // Get the first input which specifies the initial iterate.
49     Iterate x0(mxDuplicateArray(prhs[0]));
50 
51     // Get the second input which specifies the callback functions.
52     CallbackFunctions funcs(prhs[1]);
53 
54     // Create a new IPOPT application object and process the options.
55     IpoptApplication app(false);
56     Options          options(x0,app,prhs[2]);
57 
58     app.RethrowNonIpoptException(false);
59 
60     // The first output argument is the value of the optimization
61     // variables obtained at the solution.
62     plhs[0] = mxDuplicateArray(x0);
63     Iterate x(plhs[0]);
64 
65     // The second output argument stores other information, such as
66     // the exit status, the value of the Lagrange multipliers upon
67     // termination, the final state of the auxiliary data, and so on.
68     MatlabInfo info(plhs[1]);
69 
70     // Check to see whether the user provided a callback function for
71     // computing the Hessian. This is not needed in the special case
72     // when a quasi-Newton approximation to the Hessian is being used.
73     if (!options.ipoptOptions().useQuasiNewton() &&
74 	!funcs.hessianFuncIsAvailable())
75       throw MatlabException("You must supply a callback function for \
76 computing the Hessian unless you decide to use a quasi-Newton \
77 approximation to the Hessian");
78 
79     // If the user tried to use her own scaling, report an error.
80     if (options.ipoptOptions().userScaling())
81       throw MatlabException("The user-defined scaling option does not \
82 work in the MATLAB interface for IPOPT");
83 
84     // If the user supplied initial values for the Lagrange
85     // multipliers, activate the "warm start" option in IPOPT.
86     if (options.multlb() && options.multub() &&
87 	(numconstraints(options)==0 || options.multconstr()) )
88       app.Options()->SetStringValue("warm_start_init_point","yes");
89 
90     // Set up the IPOPT console.
91     EJournalLevel printLevel = (EJournalLevel)
92       options.ipoptOptions().printLevel();
93     if(printLevel > 0) { //prevents IPOPT display if we don't want it
94         SmartPtr<Journal> console = new MatlabJournal(printLevel);
95         app.Jnlst()->AddJournal(console);
96     }
97 
98     // Intialize the IpoptApplication object and process the options.
99     ApplicationReturnStatus exitstatus;
100     exitstatus = app.Initialize();
101     if (exitstatus != Ipopt::Solve_Succeeded)
102       throw MatlabException("IPOPT solver initialization failed");
103 
104     // Create a new instance of the constrained, nonlinear program.
105     MatlabProgram* matlabProgram
106       = new MatlabProgram(x0,funcs,options,x,info);
107     SmartPtr<TNLP> program = matlabProgram;
108 
109     // Ask Ipopt to solve the problem.
110     exitstatus = app.OptimizeTNLP(program);
111     info.setExitStatus(exitstatus);
112 
113     // Collect statistics about Ipopt run
114     if (IsValid(app.Statistics())) {
115       SmartPtr<SolveStatistics> stats = app.Statistics();
116       info.setIterationCount(stats->IterationCount());
117       //Get Function Calls
118       int obj, con, grad, jac, hess;
119       stats->NumberOfEvaluations(obj,con,grad,jac,hess);
120       info.setFuncEvals(obj, con, grad, jac, hess);
121       //CPU Time
122       info.setCpuTime(stats->TotalCpuTime());
123     }
124 
125     // Free the dynamically allocated memory.
126     mxDestroyArray(x0);
127 
128   } catch (std::exception& error) {
129     mexErrMsgTxt(error.what());
130   }
131