1 | /* ////////////////////////////////////////////////////////////////////////////////
|
---|
2 | //
|
---|
3 | // Matlab MEX file for the Levenberg - Marquardt minimization algorithm
|
---|
4 | // Copyright (C) 2007 Manolis Lourakis (lourakis at ics forth gr)
|
---|
5 | // Institute of Computer Science, Foundation for Research & Technology - Hellas
|
---|
6 | // Heraklion, Crete, Greece.
|
---|
7 | //
|
---|
8 | // This program is free software; you can redistribute it and/or modify
|
---|
9 | // it under the terms of the GNU General Public License as published by
|
---|
10 | // the Free Software Foundation; either version 2 of the License, or
|
---|
11 | // (at your option) any later version.
|
---|
12 | //
|
---|
13 | // This program is distributed in the hope that it will be useful,
|
---|
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
16 | // GNU General Public License for more details.
|
---|
17 | //
|
---|
18 | //////////////////////////////////////////////////////////////////////////////// */
|
---|
19 |
|
---|
20 | #include <stdio.h>
|
---|
21 | #include <stdlib.h>
|
---|
22 | #include <stdarg.h>
|
---|
23 | #include <math.h>
|
---|
24 | #include <string.h>
|
---|
25 | #include <ctype.h>
|
---|
26 |
|
---|
27 | #include <levmar.h>
|
---|
28 |
|
---|
29 | #include <mex.h>
|
---|
30 |
|
---|
31 | /**
|
---|
32 | #define DEBUG
|
---|
33 | **/
|
---|
34 |
|
---|
35 | #ifndef HAVE_LAPACK
|
---|
36 | #ifdef _MSC_VER
|
---|
37 | #pragma message("LAPACK not available, certain functionalities cannot be compiled!")
|
---|
38 | #else
|
---|
39 | #warning LAPACK not available, certain functionalities cannot be compiled
|
---|
40 | #endif /* _MSC_VER */
|
---|
41 | #endif /* HAVE_LAPACK */
|
---|
42 |
|
---|
43 | #define __MAX__(A, B) ((A)>=(B)? (A) : (B))
|
---|
44 |
|
---|
45 | #define MIN_UNCONSTRAINED 0
|
---|
46 | #define MIN_CONSTRAINED_BC 1
|
---|
47 | #define MIN_CONSTRAINED_LEC 2
|
---|
48 | #define MIN_CONSTRAINED_BLEC 3
|
---|
49 | #define MIN_CONSTRAINED_BLEIC 4
|
---|
50 | #define MIN_CONSTRAINED_BLIC 5
|
---|
51 | #define MIN_CONSTRAINED_LEIC 6
|
---|
52 | #define MIN_CONSTRAINED_LIC 7
|
---|
53 |
|
---|
54 | struct mexdata {
|
---|
55 | /* matlab names of the fitting function & its Jacobian */
|
---|
56 | char *fname, *jacname;
|
---|
57 |
|
---|
58 | /* binary flags specifying if input p0 is a row or column vector */
|
---|
59 | int isrow_p0;
|
---|
60 |
|
---|
61 | /* rhs args to be passed to matlab. rhs[0] is reserved for
|
---|
62 | * passing the parameter vector. If present, problem-specific
|
---|
63 | * data are passed in rhs[1], rhs[2], etc
|
---|
64 | */
|
---|
65 | mxArray **rhs;
|
---|
66 | int nrhs; /* >= 1 */
|
---|
67 | };
|
---|
68 |
|
---|
69 | /* display printf-style error messages in matlab */
|
---|
70 | static void matlabFmtdErrMsgTxt(char *fmt, ...)
|
---|
71 | {
|
---|
72 | char buf[256];
|
---|
73 | va_list args;
|
---|
74 |
|
---|
75 | va_start(args, fmt);
|
---|
76 | vsprintf(buf, fmt, args);
|
---|
77 | va_end(args);
|
---|
78 |
|
---|
79 | mexErrMsgTxt(buf);
|
---|
80 | }
|
---|
81 |
|
---|
82 | /* display printf-style warning messages in matlab */
|
---|
83 | static void matlabFmtdWarnMsgTxt(char *fmt, ...)
|
---|
84 | {
|
---|
85 | char buf[256];
|
---|
86 | va_list args;
|
---|
87 |
|
---|
88 | va_start(args, fmt);
|
---|
89 | vsprintf(buf, fmt, args);
|
---|
90 | va_end(args);
|
---|
91 |
|
---|
92 | mexWarnMsgTxt(buf);
|
---|
93 | }
|
---|
94 |
|
---|
95 | static void func(double *p, double *hx, int m, int n, void *adata)
|
---|
96 | {
|
---|
97 | mxArray *lhs[1];
|
---|
98 | double *mp, *mx;
|
---|
99 | register int i;
|
---|
100 | struct mexdata *dat=(struct mexdata *)adata;
|
---|
101 |
|
---|
102 | /* prepare to call matlab */
|
---|
103 | mp=mxGetPr(dat->rhs[0]);
|
---|
104 | for(i=0; i<m; ++i)
|
---|
105 | mp[i]=p[i];
|
---|
106 |
|
---|
107 | /* invoke matlab */
|
---|
108 | mexCallMATLAB(1, lhs, dat->nrhs, dat->rhs, dat->fname);
|
---|
109 |
|
---|
110 | /* copy back results & cleanup */
|
---|
111 | mx=mxGetPr(lhs[0]);
|
---|
112 | for(i=0; i<n; ++i)
|
---|
113 | hx[i]=mx[i];
|
---|
114 |
|
---|
115 | /* delete the matrix created by matlab */
|
---|
116 | mxDestroyArray(lhs[0]);
|
---|
117 | }
|
---|
118 |
|
---|
119 | static void jacfunc(double *p, double *j, int m, int n, void *adata)
|
---|
120 | {
|
---|
121 | mxArray *lhs[1];
|
---|
122 | double *mp;
|
---|
123 | double *mj;
|
---|
124 | register int i, k;
|
---|
125 | struct mexdata *dat=(struct mexdata *)adata;
|
---|
126 |
|
---|
127 | /* prepare to call matlab */
|
---|
128 | mp=mxGetPr(dat->rhs[0]);
|
---|
129 | for(i=0; i<m; ++i)
|
---|
130 | mp[i]=p[i];
|
---|
131 |
|
---|
132 | /* invoke matlab */
|
---|
133 | mexCallMATLAB(1, lhs, dat->nrhs, dat->rhs, dat->jacname);
|
---|
134 |
|
---|
135 | /* copy back results & cleanup. Note that the nxm Jacobian
|
---|
136 | * computed by matlab should be transposed so that
|
---|
137 | * levmar gets it in row major, as expected
|
---|
138 | */
|
---|
139 | mj=mxGetPr(lhs[0]);
|
---|
140 | for(i=0; i<n; ++i)
|
---|
141 | for(k=0; k<m; ++k)
|
---|
142 | j[i*m+k]=mj[i+k*n];
|
---|
143 |
|
---|
144 | /* delete the matrix created by matlab */
|
---|
145 | mxDestroyArray(lhs[0]);
|
---|
146 | }
|
---|
147 |
|
---|
148 | /* matlab matrices are in column-major, this routine converts them to row major for levmar */
|
---|
149 | static double *getTranspose(mxArray *Am)
|
---|
150 | {
|
---|
151 | int m, n;
|
---|
152 | double *At, *A;
|
---|
153 | register int i, j;
|
---|
154 |
|
---|
155 | m=mxGetM(Am);
|
---|
156 | n=mxGetN(Am);
|
---|
157 | A=mxGetPr(Am);
|
---|
158 | At=mxMalloc(m*n*sizeof(double));
|
---|
159 |
|
---|
160 | for(i=0; i<m; i++)
|
---|
161 | for(j=0; j<n; j++)
|
---|
162 | At[i*n+j]=A[i+j*m];
|
---|
163 |
|
---|
164 | return At;
|
---|
165 | }
|
---|
166 |
|
---|
167 | /* check the supplied matlab function and its Jacobian. Returns 1 on error, 0 otherwise */
|
---|
168 | static int checkFuncAndJacobian(double *p, int m, int n, int havejac, struct mexdata *dat)
|
---|
169 | {
|
---|
170 | mxArray *lhs[1];
|
---|
171 | register int i;
|
---|
172 | int ret=0;
|
---|
173 | double *mp;
|
---|
174 |
|
---|
175 | mexSetTrapFlag(1); /* handle errors in the MEX-file */
|
---|
176 |
|
---|
177 | mp=mxGetPr(dat->rhs[0]);
|
---|
178 | for(i=0; i<m; ++i)
|
---|
179 | mp[i]=p[i];
|
---|
180 |
|
---|
181 | /* attempt to call the supplied func */
|
---|
182 | i=mexCallMATLAB(1, lhs, dat->nrhs, dat->rhs, dat->fname);
|
---|
183 | if(i){
|
---|
184 | fprintf(stderr, "levmar: error calling '%s'.\n", dat->fname);
|
---|
185 | ret=1;
|
---|
186 | }
|
---|
187 | else if(!mxIsDouble(lhs[0]) || mxIsComplex(lhs[0]) || !(mxGetM(lhs[0])==1 || mxGetN(lhs[0])==1) ||
|
---|
188 | __MAX__(mxGetM(lhs[0]), mxGetN(lhs[0]))!=n){
|
---|
189 | fprintf(stderr, "levmar: '%s' should produce a real vector with %d elements (got %d).\n",
|
---|
190 | dat->fname, n, __MAX__(mxGetM(lhs[0]), mxGetN(lhs[0])));
|
---|
191 | ret=1;
|
---|
192 | }
|
---|
193 | /* delete the matrix created by matlab */
|
---|
194 | mxDestroyArray(lhs[0]);
|
---|
195 |
|
---|
196 | if(havejac){
|
---|
197 | /* attempt to call the supplied jac */
|
---|
198 | i=mexCallMATLAB(1, lhs, dat->nrhs, dat->rhs, dat->jacname);
|
---|
199 | if(i){
|
---|
200 | fprintf(stderr, "levmar: error calling '%s'.\n", dat->jacname);
|
---|
201 | ret=1;
|
---|
202 | }
|
---|
203 | else if(!mxIsDouble(lhs[0]) || mxIsComplex(lhs[0]) || mxGetM(lhs[0])!=n || mxGetN(lhs[0])!=m){
|
---|
204 | fprintf(stderr, "levmar: '%s' should produce a real %dx%d matrix (got %dx%d).\n",
|
---|
205 | dat->jacname, n, m, mxGetM(lhs[0]), mxGetN(lhs[0]));
|
---|
206 | ret=1;
|
---|
207 | }
|
---|
208 | else if(mxIsSparse(lhs[0])){
|
---|
209 | fprintf(stderr, "levmar: '%s' should produce a real dense matrix (got a sparse one).\n", dat->jacname);
|
---|
210 | ret=1;
|
---|
211 | }
|
---|
212 | /* delete the matrix created by matlab */
|
---|
213 | mxDestroyArray(lhs[0]);
|
---|
214 | }
|
---|
215 |
|
---|
216 | mexSetTrapFlag(0); /* on error terminate the MEX-file and return control to the MATLAB prompt */
|
---|
217 |
|
---|
218 | return ret;
|
---|
219 | }
|
---|
220 |
|
---|
221 |
|
---|
222 | /*
|
---|
223 | [ret, p, info, covar]=levmar_der (f, j, p0, x, itmax, opts, 'unc' ...)
|
---|
224 | [ret, p, info, covar]=levmar_bc (f, j, p0, x, itmax, opts, 'bc', lb, ub, ...)
|
---|
225 | [ret, p, info, covar]=levmar_bc (f, j, p0, x, itmax, opts, 'bc', lb, ub, dscl, ...)
|
---|
226 | [ret, p, info, covar]=levmar_lec (f, j, p0, x, itmax, opts, 'lec', A, b, ...)
|
---|
227 | [ret, p, info, covar]=levmar_blec(f, j, p0, x, itmax, opts, 'blec', lb, ub, A, b, wghts, ...)
|
---|
228 |
|
---|
229 | [ret, p, info, covar]=levmar_bleic(f, j, p0, x, itmax, opts, 'bleic', lb, ub, A, b, C, d, ...)
|
---|
230 | [ret, p, info, covar]=levmar_blic (f, j, p0, x, itmax, opts, 'blic', lb, ub, C, d, ...)
|
---|
231 | [ret, p, info, covar]=levmar_leic (f, j, p0, x, itmax, opts, 'leic', A, b, C, d, ...)
|
---|
232 | [ret, p, info, covar]=levmar_lic (f, j, p0, x, itmax, opts, 'lic', C, d, ...)
|
---|
233 |
|
---|
234 | */
|
---|
235 |
|
---|
236 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *Prhs[])
|
---|
237 | {
|
---|
238 | register int i;
|
---|
239 | register double *pdbl;
|
---|
240 | mxArray **prhs=(mxArray **)&Prhs[0], *At, *Ct;
|
---|
241 | struct mexdata mdata;
|
---|
242 | int len, status;
|
---|
243 | double *p, *p0, *ret, *x;
|
---|
244 | int m, n, havejac, Arows, Crows, itmax, nopts, mintype, nextra;
|
---|
245 | double opts[LM_OPTS_SZ]={LM_INIT_MU, LM_STOP_THRESH, LM_STOP_THRESH, LM_STOP_THRESH, LM_DIFF_DELTA};
|
---|
246 | double info[LM_INFO_SZ];
|
---|
247 | double *lb=NULL, *ub=NULL, *dscl=NULL, *A=NULL, *b=NULL, *wghts=NULL, *C=NULL, *d=NULL, *covar=NULL;
|
---|
248 |
|
---|
249 | /* parse input args; start by checking their number */
|
---|
250 | if((nrhs<5))
|
---|
251 | matlabFmtdErrMsgTxt("levmar: at least 5 input arguments required (got %d).", nrhs);
|
---|
252 | if(nlhs>4)
|
---|
253 | matlabFmtdErrMsgTxt("levmar: too many output arguments (max. 4, got %d).", nlhs);
|
---|
254 | else if(nlhs<2)
|
---|
255 | matlabFmtdErrMsgTxt("levmar: too few output arguments (min. 2, got %d).", nlhs);
|
---|
256 |
|
---|
257 | /* note that in order to accommodate optional args, prhs & nrhs are adjusted accordingly below */
|
---|
258 |
|
---|
259 | /** func **/
|
---|
260 | /* first argument must be a string , i.e. a char row vector */
|
---|
261 | if(mxIsChar(prhs[0])!=1)
|
---|
262 | mexErrMsgTxt("levmar: first argument must be a string.");
|
---|
263 | if(mxGetM(prhs[0])!=1)
|
---|
264 | mexErrMsgTxt("levmar: first argument must be a string (i.e. char row vector).");
|
---|
265 | /* store supplied name */
|
---|
266 | len=mxGetN(prhs[0])+1;
|
---|
267 | mdata.fname=mxCalloc(len, sizeof(char));
|
---|
268 | status=mxGetString(prhs[0], mdata.fname, len);
|
---|
269 | if(status!=0)
|
---|
270 | mexErrMsgTxt("levmar: not enough space. String is truncated.");
|
---|
271 |
|
---|
272 | /** jac (optional) **/
|
---|
273 | /* check whether second argument is a string */
|
---|
274 | if(mxIsChar(prhs[1])==1){
|
---|
275 | if(mxGetM(prhs[1])!=1)
|
---|
276 | mexErrMsgTxt("levmar: second argument must be a string (i.e. row vector).");
|
---|
277 | /* store supplied name */
|
---|
278 | len=mxGetN(prhs[1])+1;
|
---|
279 | mdata.jacname=mxCalloc(len, sizeof(char));
|
---|
280 | status=mxGetString(prhs[1], mdata.jacname, len);
|
---|
281 | if(status!=0)
|
---|
282 | mexErrMsgTxt("levmar: not enough space. String is truncated.");
|
---|
283 | havejac=1;
|
---|
284 |
|
---|
285 | ++prhs;
|
---|
286 | --nrhs;
|
---|
287 | }
|
---|
288 | else{
|
---|
289 | mdata.jacname=NULL;
|
---|
290 | havejac=0;
|
---|
291 | }
|
---|
292 |
|
---|
293 | #ifdef DEBUG
|
---|
294 | fflush(stderr);
|
---|
295 | fprintf(stderr, "LEVMAR: %s analytic Jacobian\n", havejac? "with" : "no");
|
---|
296 | #endif /* DEBUG */
|
---|
297 |
|
---|
298 | /* CHECK
|
---|
299 | if(!mxIsDouble(prhs[1]) || mxIsComplex(prhs[1]) || !(mxGetM(prhs[1])==1 && mxGetN(prhs[1])==1))
|
---|
300 | */
|
---|
301 |
|
---|
302 | /** p0 **/
|
---|
303 | /* the second required argument must be a real row or column vector */
|
---|
304 | if(!mxIsDouble(prhs[1]) || mxIsComplex(prhs[1]) || !(mxGetM(prhs[1])==1 || mxGetN(prhs[1])==1))
|
---|
305 | mexErrMsgTxt("levmar: p0 must be a real vector.");
|
---|
306 | p0=mxGetPr(prhs[1]);
|
---|
307 | /* determine if we have a row or column vector and retrieve its
|
---|
308 | * size, i.e. the number of parameters
|
---|
309 | */
|
---|
310 | if(mxGetM(prhs[1])==1){
|
---|
311 | m=mxGetN(prhs[1]);
|
---|
312 | mdata.isrow_p0=1;
|
---|
313 | }
|
---|
314 | else{
|
---|
315 | m=mxGetM(prhs[1]);
|
---|
316 | mdata.isrow_p0=0;
|
---|
317 | }
|
---|
318 | /* copy input parameter vector to avoid destroying it */
|
---|
319 | p=mxMalloc(m*sizeof(double));
|
---|
320 | for(i=0; i<m; ++i)
|
---|
321 | p[i]=p0[i];
|
---|
322 |
|
---|
323 | /** x **/
|
---|
324 | /* the third required argument must be a real row or column vector */
|
---|
325 | if(!mxIsDouble(prhs[2]) || mxIsComplex(prhs[2]) || !(mxGetM(prhs[2])==1 || mxGetN(prhs[2])==1))
|
---|
326 | mexErrMsgTxt("levmar: x must be a real vector.");
|
---|
327 | x=mxGetPr(prhs[2]);
|
---|
328 | n=__MAX__(mxGetM(prhs[2]), mxGetN(prhs[2]));
|
---|
329 |
|
---|
330 | /** itmax **/
|
---|
331 | /* the fourth required argument must be a scalar */
|
---|
332 | if(!mxIsDouble(prhs[3]) || mxIsComplex(prhs[3]) || mxGetM(prhs[3])!=1 || mxGetN(prhs[3])!=1)
|
---|
333 | mexErrMsgTxt("levmar: itmax must be a scalar.");
|
---|
334 | itmax=(int)mxGetScalar(prhs[3]);
|
---|
335 |
|
---|
336 | /** opts **/
|
---|
337 | /* the fifth required argument must be a real row or column vector */
|
---|
338 | if(!mxIsDouble(prhs[4]) || mxIsComplex(prhs[4]) || (!(mxGetM(prhs[4])==1 || mxGetN(prhs[4])==1) &&
|
---|
339 | !(mxGetM(prhs[4])==0 && mxGetN(prhs[4])==0)))
|
---|
340 | mexErrMsgTxt("levmar: opts must be a real vector.");
|
---|
341 | pdbl=mxGetPr(prhs[4]);
|
---|
342 | nopts=__MAX__(mxGetM(prhs[4]), mxGetN(prhs[4]));
|
---|
343 | if(nopts!=0){ /* if opts==[], nothing needs to be done and the defaults are used */
|
---|
344 | if(nopts>LM_OPTS_SZ)
|
---|
345 | matlabFmtdErrMsgTxt("levmar: opts must have at most %d elements, got %d.", LM_OPTS_SZ, nopts);
|
---|
346 | else if(nopts<((havejac)? LM_OPTS_SZ-1 : LM_OPTS_SZ))
|
---|
347 | matlabFmtdWarnMsgTxt("levmar: only the %d first elements of opts specified, remaining set to defaults.", nopts);
|
---|
348 | for(i=0; i<nopts; ++i)
|
---|
349 | opts[i]=pdbl[i];
|
---|
350 | }
|
---|
351 | #ifdef DEBUG
|
---|
352 | else{
|
---|
353 | fflush(stderr);
|
---|
354 | fprintf(stderr, "LEVMAR: empty options vector, using defaults\n");
|
---|
355 | }
|
---|
356 | #endif /* DEBUG */
|
---|
357 |
|
---|
358 | /** mintype (optional) **/
|
---|
359 | /* check whether sixth argument is a string */
|
---|
360 | if(nrhs>=6 && mxIsChar(prhs[5])==1 && mxGetM(prhs[5])==1){
|
---|
361 | char *minhowto;
|
---|
362 |
|
---|
363 | /* examine supplied name */
|
---|
364 | len=mxGetN(prhs[5])+1;
|
---|
365 | minhowto=mxCalloc(len, sizeof(char));
|
---|
366 | status=mxGetString(prhs[5], minhowto, len);
|
---|
367 | if(status!=0)
|
---|
368 | mexErrMsgTxt("levmar: not enough space. String is truncated.");
|
---|
369 |
|
---|
370 | for(i=0; minhowto[i]; ++i)
|
---|
371 | minhowto[i]=tolower(minhowto[i]);
|
---|
372 | if(!strncmp(minhowto, "unc", 3)) mintype=MIN_UNCONSTRAINED;
|
---|
373 | else if(!strncmp(minhowto, "bc", 2)) mintype=MIN_CONSTRAINED_BC;
|
---|
374 | else if(!strncmp(minhowto, "lec", 3)) mintype=MIN_CONSTRAINED_LEC;
|
---|
375 | else if(!strncmp(minhowto, "blec", 4)) mintype=MIN_CONSTRAINED_BLEC;
|
---|
376 | else if(!strncmp(minhowto, "bleic", 5)) mintype=MIN_CONSTRAINED_BLEIC;
|
---|
377 | else if(!strncmp(minhowto, "blic", 4)) mintype=MIN_CONSTRAINED_BLIC;
|
---|
378 | else if(!strncmp(minhowto, "leic", 4)) mintype=MIN_CONSTRAINED_LEIC;
|
---|
379 | else if(!strncmp(minhowto, "lic", 3)) mintype=MIN_CONSTRAINED_BLIC;
|
---|
380 | else matlabFmtdErrMsgTxt("levmar: unknown minimization type '%s'.", minhowto);
|
---|
381 |
|
---|
382 | mxFree(minhowto);
|
---|
383 |
|
---|
384 | ++prhs;
|
---|
385 | --nrhs;
|
---|
386 | }
|
---|
387 | else
|
---|
388 | mintype=MIN_UNCONSTRAINED;
|
---|
389 |
|
---|
390 | if(mintype==MIN_UNCONSTRAINED) goto extraargs;
|
---|
391 |
|
---|
392 | /* arguments below this point are optional and their presence depends
|
---|
393 | * upon the minimization type determined above
|
---|
394 | */
|
---|
395 | /** lb, ub **/
|
---|
396 | if(nrhs>=7 && (mintype==MIN_CONSTRAINED_BC || mintype==MIN_CONSTRAINED_BLEC || mintype==MIN_CONSTRAINED_BLIC || mintype==MIN_CONSTRAINED_BLEIC)){
|
---|
397 | /* check if the next two arguments are real row or column vectors */
|
---|
398 | if(mxIsDouble(prhs[5]) && !mxIsComplex(prhs[5]) && (mxGetM(prhs[5])==1 || mxGetN(prhs[5])==1)){
|
---|
399 | if(mxIsDouble(prhs[6]) && !mxIsComplex(prhs[6]) && (mxGetM(prhs[6])==1 || mxGetN(prhs[6])==1)){
|
---|
400 | if((i=__MAX__(mxGetM(prhs[5]), mxGetN(prhs[5])))!=m)
|
---|
401 | matlabFmtdErrMsgTxt("levmar: lb must have %d elements, got %d.", m, i);
|
---|
402 | if((i=__MAX__(mxGetM(prhs[6]), mxGetN(prhs[6])))!=m)
|
---|
403 | matlabFmtdErrMsgTxt("levmar: ub must have %d elements, got %d.", m, i);
|
---|
404 |
|
---|
405 | lb=mxGetPr(prhs[5]);
|
---|
406 | ub=mxGetPr(prhs[6]);
|
---|
407 |
|
---|
408 | prhs+=2;
|
---|
409 | nrhs-=2;
|
---|
410 | }
|
---|
411 | }
|
---|
412 | }
|
---|
413 |
|
---|
414 | /** dscl **/
|
---|
415 | if(nrhs>=7 && (mintype==MIN_CONSTRAINED_BC)){
|
---|
416 | /* check if the next argument is a real row or column vector */
|
---|
417 | if(mxIsDouble(prhs[5]) && !mxIsComplex(prhs[5]) && (mxGetM(prhs[5])==1 || mxGetN(prhs[5])==1)){
|
---|
418 | if((i=__MAX__(mxGetM(prhs[5]), mxGetN(prhs[5])))!=m)
|
---|
419 | matlabFmtdErrMsgTxt("levmar: dscl must have %d elements, got %d.", m, i);
|
---|
420 |
|
---|
421 | dscl=mxGetPr(prhs[5]);
|
---|
422 |
|
---|
423 | ++prhs;
|
---|
424 | --nrhs;
|
---|
425 | }
|
---|
426 | }
|
---|
427 |
|
---|
428 | /** A, b **/
|
---|
429 | if(nrhs>=7 && (mintype==MIN_CONSTRAINED_LEC || mintype==MIN_CONSTRAINED_BLEC || mintype==MIN_CONSTRAINED_LEIC || mintype==MIN_CONSTRAINED_BLEIC)){
|
---|
430 | /* check if the next two arguments are a real matrix and a real row or column vector */
|
---|
431 | if(mxIsDouble(prhs[5]) && !mxIsComplex(prhs[5]) && mxGetM(prhs[5])>=1 && mxGetN(prhs[5])>=1){
|
---|
432 | if(mxIsDouble(prhs[6]) && !mxIsComplex(prhs[6]) && (mxGetM(prhs[6])==1 || mxGetN(prhs[6])==1)){
|
---|
433 | if((i=mxGetN(prhs[5]))!=m)
|
---|
434 | matlabFmtdErrMsgTxt("levmar: A must have %d columns, got %d.", m, i);
|
---|
435 | if((i=__MAX__(mxGetM(prhs[6]), mxGetN(prhs[6])))!=(Arows=mxGetM(prhs[5])))
|
---|
436 | matlabFmtdErrMsgTxt("levmar: b must have %d elements, got %d.", Arows, i);
|
---|
437 |
|
---|
438 | At=prhs[5];
|
---|
439 | b=mxGetPr(prhs[6]);
|
---|
440 | A=getTranspose(At);
|
---|
441 |
|
---|
442 | prhs+=2;
|
---|
443 | nrhs-=2;
|
---|
444 | }
|
---|
445 | }
|
---|
446 | }
|
---|
447 |
|
---|
448 | /* wghts */
|
---|
449 | /* check if we have a weights vector */
|
---|
450 | if(nrhs>=6 && mintype==MIN_CONSTRAINED_BLEC){ /* only check if we have seen both box & linear constraints */
|
---|
451 | if(mxIsDouble(prhs[5]) && !mxIsComplex(prhs[5]) && (mxGetM(prhs[5])==1 || mxGetN(prhs[5])==1)){
|
---|
452 | if(__MAX__(mxGetM(prhs[5]), mxGetN(prhs[5]))==m){
|
---|
453 | wghts=mxGetPr(prhs[5]);
|
---|
454 |
|
---|
455 | ++prhs;
|
---|
456 | --nrhs;
|
---|
457 | }
|
---|
458 | }
|
---|
459 | }
|
---|
460 |
|
---|
461 | /** C, d **/
|
---|
462 | if(nrhs>=7 && (mintype==MIN_CONSTRAINED_BLEIC || mintype==MIN_CONSTRAINED_BLIC || mintype==MIN_CONSTRAINED_LEIC || mintype==MIN_CONSTRAINED_LIC)){
|
---|
463 | /* check if the next two arguments are a real matrix and a real row or column vector */
|
---|
464 | if(mxIsDouble(prhs[5]) && !mxIsComplex(prhs[5]) && mxGetM(prhs[5])>=1 && mxGetN(prhs[5])>=1){
|
---|
465 | if(mxIsDouble(prhs[6]) && !mxIsComplex(prhs[6]) && (mxGetM(prhs[6])==1 || mxGetN(prhs[6])==1)){
|
---|
466 | if((i=mxGetN(prhs[5]))!=m)
|
---|
467 | matlabFmtdErrMsgTxt("levmar: C must have %d columns, got %d.", m, i);
|
---|
468 | if((i=__MAX__(mxGetM(prhs[6]), mxGetN(prhs[6])))!=(Crows=mxGetM(prhs[5])))
|
---|
469 | matlabFmtdErrMsgTxt("levmar: d must have %d elements, got %d.", Crows, i);
|
---|
470 |
|
---|
471 | Ct=prhs[5];
|
---|
472 | d=mxGetPr(prhs[6]);
|
---|
473 | C=getTranspose(Ct);
|
---|
474 |
|
---|
475 | prhs+=2;
|
---|
476 | nrhs-=2;
|
---|
477 | }
|
---|
478 | }
|
---|
479 | }
|
---|
480 |
|
---|
481 | /* arguments below this point are assumed to be extra arguments passed
|
---|
482 | * to every invocation of the fitting function and its Jacobian
|
---|
483 | */
|
---|
484 |
|
---|
485 | extraargs:
|
---|
486 | /* handle any extra args and allocate memory for
|
---|
487 | * passing the current parameter estimate to matlab
|
---|
488 | */
|
---|
489 | nextra=nrhs-5;
|
---|
490 | mdata.nrhs=nextra+1;
|
---|
491 | mdata.rhs=(mxArray **)mxMalloc(mdata.nrhs*sizeof(mxArray *));
|
---|
492 | for(i=0; i<nextra; ++i)
|
---|
493 | mdata.rhs[i+1]=(mxArray *)prhs[nrhs-nextra+i]; /* discard 'const' modifier */
|
---|
494 | #ifdef DEBUG
|
---|
495 | fflush(stderr);
|
---|
496 | fprintf(stderr, "LEVMAR: %d extra args\n", nextra);
|
---|
497 | #endif /* DEBUG */
|
---|
498 |
|
---|
499 | if(mdata.isrow_p0){ /* row vector */
|
---|
500 | mdata.rhs[0]=mxCreateDoubleMatrix(1, m, mxREAL);
|
---|
501 | /*
|
---|
502 | mxSetM(mdata.rhs[0], 1);
|
---|
503 | mxSetN(mdata.rhs[0], m);
|
---|
504 | */
|
---|
505 | }
|
---|
506 | else{ /* column vector */
|
---|
507 | mdata.rhs[0]=mxCreateDoubleMatrix(m, 1, mxREAL);
|
---|
508 | /*
|
---|
509 | mxSetM(mdata.rhs[0], m);
|
---|
510 | mxSetN(mdata.rhs[0], 1);
|
---|
511 | */
|
---|
512 | }
|
---|
513 |
|
---|
514 | /* ensure that the supplied function & Jacobian are as expected */
|
---|
515 | if(checkFuncAndJacobian(p, m, n, havejac, &mdata)){
|
---|
516 | status=LM_ERROR;
|
---|
517 | goto cleanup;
|
---|
518 | }
|
---|
519 |
|
---|
520 | if(nlhs>3) /* covariance output required */
|
---|
521 | covar=mxMalloc(m*m*sizeof(double));
|
---|
522 |
|
---|
523 | /* invoke levmar */
|
---|
524 | switch(mintype){
|
---|
525 | case MIN_UNCONSTRAINED: /* no constraints */
|
---|
526 | if(havejac)
|
---|
527 | status=dlevmar_der(func, jacfunc, p, x, m, n, itmax, opts, info, NULL, covar, (void *)&mdata);
|
---|
528 | else
|
---|
529 | status=dlevmar_dif(func, p, x, m, n, itmax, opts, info, NULL, covar, (void *)&mdata);
|
---|
530 | #ifdef DEBUG
|
---|
531 | fflush(stderr);
|
---|
532 | fprintf(stderr, "LEVMAR: calling dlevmar_der()/dlevmar_dif()\n");
|
---|
533 | #endif /* DEBUG */
|
---|
534 | break;
|
---|
535 | case MIN_CONSTRAINED_BC: /* box constraints */
|
---|
536 | if(havejac)
|
---|
537 | status=dlevmar_bc_der(func, jacfunc, p, x, m, n, lb, ub, dscl, itmax, opts, info, NULL, covar, (void *)&mdata);
|
---|
538 | else
|
---|
539 | status=dlevmar_bc_dif(func, p, x, m, n, lb, ub, dscl, itmax, opts, info, NULL, covar, (void *)&mdata);
|
---|
540 | #ifdef DEBUG
|
---|
541 | fflush(stderr);
|
---|
542 | fprintf(stderr, "LEVMAR: calling dlevmar_bc_der()/dlevmar_bc_dif()\n");
|
---|
543 | #endif /* DEBUG */
|
---|
544 | break;
|
---|
545 | case MIN_CONSTRAINED_LEC: /* linear equation constraints */
|
---|
546 | #ifdef HAVE_LAPACK
|
---|
547 | if(havejac)
|
---|
548 | status=dlevmar_lec_der(func, jacfunc, p, x, m, n, A, b, Arows, itmax, opts, info, NULL, covar, (void *)&mdata);
|
---|
549 | else
|
---|
550 | status=dlevmar_lec_dif(func, p, x, m, n, A, b, Arows, itmax, opts, info, NULL, covar, (void *)&mdata);
|
---|
551 | #else
|
---|
552 | mexErrMsgTxt("levmar: no linear constraints support, HAVE_LAPACK was not defined during MEX-file compilation.");
|
---|
553 | #endif /* HAVE_LAPACK */
|
---|
554 |
|
---|
555 | #ifdef DEBUG
|
---|
556 | fflush(stderr);
|
---|
557 | fprintf(stderr, "LEVMAR: calling dlevmar_lec_der()/dlevmar_lec_dif()\n");
|
---|
558 | #endif /* DEBUG */
|
---|
559 | break;
|
---|
560 | case MIN_CONSTRAINED_BLEC: /* box & linear equation constraints */
|
---|
561 | #ifdef HAVE_LAPACK
|
---|
562 | if(havejac)
|
---|
563 | status=dlevmar_blec_der(func, jacfunc, p, x, m, n, lb, ub, A, b, Arows, wghts, itmax, opts, info, NULL, covar, (void *)&mdata);
|
---|
564 | else
|
---|
565 | status=dlevmar_blec_dif(func, p, x, m, n, lb, ub, A, b, Arows, wghts, itmax, opts, info, NULL, covar, (void *)&mdata);
|
---|
566 | #else
|
---|
567 | mexErrMsgTxt("levmar: no box & linear constraints support, HAVE_LAPACK was not defined during MEX-file compilation.");
|
---|
568 | #endif /* HAVE_LAPACK */
|
---|
569 |
|
---|
570 | #ifdef DEBUG
|
---|
571 | fflush(stderr);
|
---|
572 | fprintf(stderr, "LEVMAR: calling dlevmar_blec_der()/dlevmar_blec_dif()\n");
|
---|
573 | #endif /* DEBUG */
|
---|
574 | break;
|
---|
575 | case MIN_CONSTRAINED_BLEIC: /* box, linear equation & inequalities constraints */
|
---|
576 | #ifdef HAVE_LAPACK
|
---|
577 | if(havejac)
|
---|
578 | status=dlevmar_bleic_der(func, jacfunc, p, x, m, n, lb, ub, A, b, Arows, C, d, Crows, itmax, opts, info, NULL, covar, (void *)&mdata);
|
---|
579 | else
|
---|
580 | status=dlevmar_bleic_dif(func, p, x, m, n, lb, ub, A, b, Arows, C, d, Crows, itmax, opts, info, NULL, covar, (void *)&mdata);
|
---|
581 | #else
|
---|
582 | mexErrMsgTxt("levmar: no box, linear equation & inequality constraints support, HAVE_LAPACK was not defined during MEX-file compilation.");
|
---|
583 | #endif /* HAVE_LAPACK */
|
---|
584 |
|
---|
585 | #ifdef DEBUG
|
---|
586 | fflush(stderr);
|
---|
587 | fprintf(stderr, "LEVMAR: calling dlevmar_bleic_der()/dlevmar_bleic_dif()\n");
|
---|
588 | #endif /* DEBUG */
|
---|
589 | break;
|
---|
590 | case MIN_CONSTRAINED_BLIC: /* box, linear inequalities constraints */
|
---|
591 | #ifdef HAVE_LAPACK
|
---|
592 | if(havejac)
|
---|
593 | status=dlevmar_bleic_der(func, jacfunc, p, x, m, n, lb, ub, NULL, NULL, 0, C, d, Crows, itmax, opts, info, NULL, covar, (void *)&mdata);
|
---|
594 | else
|
---|
595 | status=dlevmar_bleic_dif(func, p, x, m, n, lb, ub, NULL, NULL, 0, C, d, Crows, itmax, opts, info, NULL, covar, (void *)&mdata);
|
---|
596 | #else
|
---|
597 | mexErrMsgTxt("levmar: no box & linear inequality constraints support, HAVE_LAPACK was not defined during MEX-file compilation.");
|
---|
598 | #endif /* HAVE_LAPACK */
|
---|
599 |
|
---|
600 | #ifdef DEBUG
|
---|
601 | fflush(stderr);
|
---|
602 | fprintf(stderr, "LEVMAR: calling dlevmar_blic_der()/dlevmar_blic_dif()\n");
|
---|
603 | #endif /* DEBUG */
|
---|
604 | break;
|
---|
605 | case MIN_CONSTRAINED_LEIC: /* linear equation & inequalities constraints */
|
---|
606 | #ifdef HAVE_LAPACK
|
---|
607 | if(havejac)
|
---|
608 | status=dlevmar_bleic_der(func, jacfunc, p, x, m, n, NULL, NULL, A, b, Arows, C, d, Crows, itmax, opts, info, NULL, covar, (void *)&mdata);
|
---|
609 | else
|
---|
610 | status=dlevmar_bleic_dif(func, p, x, m, n, NULL, NULL, A, b, Arows, C, d, Crows, itmax, opts, info, NULL, covar, (void *)&mdata);
|
---|
611 | #else
|
---|
612 | mexErrMsgTxt("levmar: no linear equation & inequality constraints support, HAVE_LAPACK was not defined during MEX-file compilation.");
|
---|
613 | #endif /* HAVE_LAPACK */
|
---|
614 |
|
---|
615 | #ifdef DEBUG
|
---|
616 | fflush(stderr);
|
---|
617 | fprintf(stderr, "LEVMAR: calling dlevmar_leic_der()/dlevmar_leic_dif()\n");
|
---|
618 | #endif /* DEBUG */
|
---|
619 | break;
|
---|
620 | case MIN_CONSTRAINED_LIC: /* linear inequalities constraints */
|
---|
621 | #ifdef HAVE_LAPACK
|
---|
622 | if(havejac)
|
---|
623 | status=dlevmar_bleic_der(func, jacfunc, p, x, m, n, NULL, NULL, NULL, NULL, 0, C, d, Crows, itmax, opts, info, NULL, covar, (void *)&mdata);
|
---|
624 | else
|
---|
625 | status=dlevmar_bleic_dif(func, p, x, m, n, NULL, NULL, NULL, NULL, 0, C, d, Crows, itmax, opts, info, NULL, covar, (void *)&mdata);
|
---|
626 | #else
|
---|
627 | mexErrMsgTxt("levmar: no linear equation & inequality constraints support, HAVE_LAPACK was not defined during MEX-file compilation.");
|
---|
628 | #endif /* HAVE_LAPACK */
|
---|
629 |
|
---|
630 | #ifdef DEBUG
|
---|
631 | fflush(stderr);
|
---|
632 | fprintf(stderr, "LEVMAR: calling dlevmar_lic_der()/dlevmar_lic_dif()\n");
|
---|
633 | #endif /* DEBUG */
|
---|
634 | break;
|
---|
635 | default:
|
---|
636 | mexErrMsgTxt("levmar: unexpected internal error.");
|
---|
637 | }
|
---|
638 |
|
---|
639 | #ifdef DEBUG
|
---|
640 | fflush(stderr);
|
---|
641 | printf("LEVMAR: minimization returned %d in %g iter, reason %g\n\tSolution: ", status, info[5], info[6]);
|
---|
642 | for(i=0; i<m; ++i)
|
---|
643 | printf("%.7g ", p[i]);
|
---|
644 | printf("\n\n\tMinimization info:\n\t");
|
---|
645 | for(i=0; i<LM_INFO_SZ; ++i)
|
---|
646 | printf("%g ", info[i]);
|
---|
647 | printf("\n");
|
---|
648 | #endif /* DEBUG */
|
---|
649 |
|
---|
650 | /* copy back return results */
|
---|
651 | /** ret **/
|
---|
652 | plhs[0]=mxCreateDoubleMatrix(1, 1, mxREAL);
|
---|
653 | ret=mxGetPr(plhs[0]);
|
---|
654 | ret[0]=(double)status;
|
---|
655 |
|
---|
656 | /** popt **/
|
---|
657 | plhs[1]=(mdata.isrow_p0==1)? mxCreateDoubleMatrix(1, m, mxREAL) : mxCreateDoubleMatrix(m, 1, mxREAL);
|
---|
658 | pdbl=mxGetPr(plhs[1]);
|
---|
659 | for(i=0; i<m; ++i)
|
---|
660 | pdbl[i]=p[i];
|
---|
661 |
|
---|
662 | /** info **/
|
---|
663 | if(nlhs>2){
|
---|
664 | plhs[2]=mxCreateDoubleMatrix(1, LM_INFO_SZ, mxREAL);
|
---|
665 | pdbl=mxGetPr(plhs[2]);
|
---|
666 | for(i=0; i<LM_INFO_SZ; ++i)
|
---|
667 | pdbl[i]=info[i];
|
---|
668 | }
|
---|
669 |
|
---|
670 | /** covar **/
|
---|
671 | if(nlhs>3){
|
---|
672 | plhs[3]=mxCreateDoubleMatrix(m, m, mxREAL);
|
---|
673 | pdbl=mxGetPr(plhs[3]);
|
---|
674 | for(i=0; i<m*m; ++i) /* covariance matrices are symmetric, thus no need to transpose! */
|
---|
675 | pdbl[i]=covar[i];
|
---|
676 | }
|
---|
677 |
|
---|
678 | cleanup:
|
---|
679 | /* cleanup */
|
---|
680 | mxDestroyArray(mdata.rhs[0]);
|
---|
681 | if(A) mxFree(A);
|
---|
682 | if(C) mxFree(C);
|
---|
683 |
|
---|
684 | mxFree(mdata.fname);
|
---|
685 | if(havejac) mxFree(mdata.jacname);
|
---|
686 | mxFree(p);
|
---|
687 | mxFree(mdata.rhs);
|
---|
688 | if(covar) mxFree(covar);
|
---|
689 |
|
---|
690 | if(status==LM_ERROR)
|
---|
691 | mexWarnMsgTxt("levmar: optimization returned with an error!");
|
---|
692 | }
|
---|