Revert "Add option to checkpoint every evaluation"
[openmx:openmx.git] / src / omxCsolnp.cpp
1 /*
2  *  Copyright 2007-2012 The OpenMx Project
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *       http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *   Unless required by applicable law or agreed to in writing, software
11  *   distributed under the License is distributed on an "AS IS" BASIS,
12  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */
16
17 #include <ctype.h>
18 #define R_NO_REMAP
19 #include <R.h>
20 #include <Rinternals.h>
21 #include "omxState.h"
22 #include "omxNPSOLSpecific.h"
23 #include "omxMatrix.h"
24 #include "glue.h"
25 #include "omxImportFrontendState.h"
26 #include "matrix.h"
27 #include "omxCsolnp.h"
28
29 static const char* anonMatrix = "anonymous matrix";
30
31 /* NPSOL-related functions */
32 //************************* npsol ****************************//
33 //int solnp(Matrix solPars, double (*solFun)(Matrix),  Matrix solEqB,  Matrix (*solEqBFun)( Matrix),  Matrix (*solEqBStartFun)(Matrix),  Matrix solLB,  Matrix solUB,  Matrix solIneqUB,  Matrix solIneqLB,  Matrix solctrl, bool debugToggle);
34
35 static omxMatrix *GLOB_fitMatrix = NULL;
36 static FitContext *GLOB_fc = NULL;
37 static int CSOLNP_currentInterval = -1;
38
39 Matrix fillMatrix(int cols, int rows, double* array)
40 {
41     Matrix t = new_matrix(cols, rows);
42         int i,j;
43         for(i=0;i<rows;i++){
44                 for(j=0;j<cols;j++) {
45                         M(t,j,i)=array[j];
46                 }
47         }
48         return t;
49 }
50
51
52 //****** Objective Function *********//
53 double csolnpObjectiveFunction(Matrix myPars, int verbose)
54 {
55         if(OMX_DEBUG) {mxLog("Starting Objective Run.");}
56     
57         omxMatrix* fitMatrix = GLOB_fitMatrix;
58     
59         R_CheckUserInterrupt();
60
61         GLOB_fc->iterations += 1;   // ought to be major iterations only
62
63         GLOB_fc->copyParamToModel(globalState, myPars.t);
64         Global->checkpointPrefit(GLOB_fc, myPars.t, false);
65     
66     omxFitFunctionCompute(fitMatrix->fitFunction, FF_COMPUTE_FIT, GLOB_fc);
67
68     if (std::isfinite(fitMatrix->data[0])) {
69             GLOB_fc->resetIterationError();
70             if (OMX_DEBUG) mxLog("Fit function returned %g", fitMatrix->data[0]);
71             GLOB_fc->fit = fitMatrix->data[0]; // redundent?
72     } else {
73             GLOB_fc->fit = 1e24;
74     }
75     
76         Global->checkpointPostfit(GLOB_fc);
77     
78         if(verbose >= 1) {
79                 mxLog("Fit function value is: %.32f", fitMatrix->data[0]);
80         }
81
82         return GLOB_fc->fit;
83 }
84
85
86 /* Objective function for confidence interval limit finding.
87  * Replaces the standard objective function when finding confidence intervals. */
88 double csolnpLimitObjectiveFunction(Matrix myPars, int verbose)
89 {
90     //double* f = NULL;
91         if (verbose >= 3) {
92                 mxLog("myPars inside obj is: ");
93         for (int i = 0; i < myPars.cols; i++)
94             mxLog("%f", myPars.t[i]);
95         }
96     
97     GLOB_fc->fit = csolnpObjectiveFunction(myPars, verbose);
98     
99     omxConfidenceInterval *oCI = &(Global->intervalList[CSOLNP_currentInterval]);
100     
101     omxRecompute(oCI->matrix);
102     
103     double CIElement = omxMatrixElement(oCI->matrix, oCI->row, oCI->col);
104     
105     if(verbose >= 2) {
106         mxLog("Finding Confidence Interval Likelihoods: lbound is %f, ubound is %f, estimate likelihood is %f, and element current value is %f.",
107               oCI->lbound, oCI->ubound, GLOB_fc->fit, CIElement);
108     }
109     
110     /* Catch boundary-passing condition */
111     if(std::isnan(CIElement) || std::isinf(CIElement)) {
112             GLOB_fc->recordIterationError("Confidence interval is in a range that is currently incalculable. Add constraints to keep the value in the region where it can be calculated.");
113         return GLOB_fc->fit;
114     }
115     
116     if(oCI->calcLower) {
117         double diff = oCI->lbound - GLOB_fc->fit;               // Offset - likelihood
118         GLOB_fc->fit = diff * diff + CIElement;
119         // Minimize element for lower bound.
120     } else {
121         double diff = oCI->ubound - GLOB_fc->fit;                       // Offset - likelihood
122         GLOB_fc->fit = diff * diff - CIElement;
123         // Maximize element for upper bound.
124     }
125     
126     if(verbose >= 2) {
127         mxLog("Interval fit function in previous iteration was calculated to be %f.", GLOB_fc->fit);
128     }
129     
130     return GLOB_fc->fit;
131 }
132
133
134 /* (Non)Linear Constraint Functions */
135 Matrix csolnpEqualityFunction(int verbose)
136 {
137         int i, j, k, eq_n = 0;
138     int l = 0;
139     double EMPTY = -999999.0;
140     Matrix myEqBFun;
141     
142     if (verbose >= 3) mxLog("Starting csolnpEqualityFunction.");
143     
144     for(j = 0; j < globalState->numConstraints; j++) {
145             if (globalState->conList[j].opCode == 1) {
146                     eq_n += globalState->conList[j].size;
147             }
148     }
149     
150     if (verbose >= 3) {
151             mxLog("no.of constraints is: %d.", globalState->numConstraints);
152             mxLog("neq is: %d.", eq_n);
153     }
154     
155     if (eq_n == 0)
156     {
157         myEqBFun = fill(1, 1, EMPTY);
158     }
159     else {
160             myEqBFun = fill(eq_n, 1, EMPTY);
161             
162             for(j = 0; j < globalState->numConstraints; j++) {
163                     if (globalState->conList[j].opCode == 1) {
164                             if (verbose >= 3) {
165                                     mxLog("result is: %2f", globalState->conList[j].result->data[0]);
166                             }
167                             omxRecompute(globalState->conList[j].result);
168                             if (verbose >= 3) {
169                                     mxLog("%.16f", globalState->conList[j].result->data[0]);
170                                     mxLog("size is: %d", globalState->conList[j].size);
171                             }
172                     }
173                     for(k = 0; k < globalState->conList[j].size; k++){
174                             M(myEqBFun,l,0) = globalState->conList[j].result->data[k];
175                             l = l + 1;
176                     }
177             }
178     }
179     if (verbose >= 3) {
180             mxLog("myEqBFun is: ");
181             for(i = 0; i < myEqBFun.cols; i++)
182         {   mxLog("%f", myEqBFun.t[i]);}
183     }
184     return myEqBFun;
185 }
186
187
188 Matrix csolnpIneqFun(int verbose)
189 {
190         int j, k, ineq_n = 0;
191     int l = 0;
192     double EMPTY = -999999.0;
193     Matrix myIneqFun;
194     
195     if (verbose >= 3) mxLog("Starting csolnpIneqFun.");
196         
197         for(j = 0; j < globalState->numConstraints; j++) {
198                 if ((globalState->conList[j].opCode == 0) || (globalState->conList[j].opCode == 2))
199         {
200             ineq_n += globalState->conList[j].size;
201         }
202     }
203     
204         if (verbose >= 3) {
205                 mxLog("no.of constraints is: %d.", globalState->numConstraints); putchar('\n');
206                 mxLog("ineq_n is: %d.", ineq_n); putchar('\n');
207         }
208     
209     if (ineq_n == 0)
210     {
211         myIneqFun = fill(1, 1, EMPTY);
212     }
213     else
214     {
215         myIneqFun = fill(ineq_n, 1, EMPTY);
216         
217         for(j = 0; j < globalState->numConstraints; j++) {
218             if ((globalState->conList[j].opCode == 0) || globalState->conList[j].opCode == 2)
219             {   omxRecompute(globalState->conList[j].result);}
220             for(k = 0; k < globalState->conList[j].size; k++){
221                 M(myIneqFun,l,0) = globalState->conList[j].result->data[k];
222                 l = l + 1;
223                 
224             }
225         }
226     }
227     
228     return myIneqFun;
229 }
230
231 void omxInvokeCSOLNP(omxMatrix *fitMatrix, FitContext *fc,
232                      int *inform_out, FreeVarGroup *freeVarGroup,
233                      int verbose, double *hessOut, double tolerance)
234
235 {
236         freeMatrices(); // maybe left overs from an aborted optimization attempt
237     
238         GLOB_fitMatrix = fitMatrix;
239         GLOB_fc = fc;
240     
241     double *x = fc->est;
242     fc->grad.resize(fc->numParam);
243     double *g = fc->grad.data();
244     
245     
246     int k;
247     int inform = 0;
248     
249     //double *cJac = NULL;    // Hessian (Approx) and Jacobian
250     
251     int ncnln = globalState->ncnln;
252     int n = int(freeVarGroup->vars.size());
253     
254     double EMPTY = -999999.0;
255     
256     Param_Obj p_obj;
257     Matrix param_hess;
258     Matrix myhess = fill(n*n, 1, (double)0.0);
259     Matrix mygrad;
260     Matrix solIneqLB;
261     Matrix solIneqUB;
262     Matrix solEqB;
263     
264     Matrix myPars = fillMatrix(n, 1, fc->est);
265     
266     double (*solFun)(struct Matrix myPars, int verbose);
267     solFun = &csolnpObjectiveFunction;
268     Matrix (*solEqBFun)(int verbose);
269     solEqBFun = &csolnpEqualityFunction;
270     Matrix (*solIneqFun)(int verbose);
271     solIneqFun = &csolnpIneqFun;
272     
273     /* Set boundaries and widths. */
274     
275     std::vector<double> blBuf(n+ncnln);
276     std::vector<double> buBuf(n+ncnln);
277     double *bl = blBuf.data();
278     double *bu = buBuf.data();
279     
280     struct Matrix myControl = fill(6,1,(double)0.0);
281     M(myControl,0,0) = 1.0;
282     M(myControl,1,0) = 400.0;
283     M(myControl,2,0) = 800.0;
284     M(myControl,3,0) = 1.0e-7;
285     M(myControl,4,0) = std::isfinite(tolerance)? tolerance : 1.0e-9;
286     M(myControl,5,0) = 0.0;
287     
288     bool myDEBUG = false;
289     /* Set up actual run */
290     
291     /* needs treatment*/
292     if (ncnln == 0)
293     {
294         solIneqLB = fill(1, 1, EMPTY);
295         solIneqUB = fill(1, 1, EMPTY);
296         solEqB = fill(1, 1, EMPTY);
297     }
298     else{
299         int j;
300         int nineqn;
301         int eqn = 0;
302         for(j = 0; j < globalState->numConstraints; j++) {
303             if (globalState->conList[j].opCode == 1)
304             {
305                 eqn += globalState->conList[j].size;
306             }
307         }
308         if (eqn == ncnln) nineqn = 1;
309         else nineqn = ncnln - eqn;
310         
311         solIneqLB = fill(nineqn, 1, EMPTY);
312         solIneqUB = fill(nineqn, 1, EMPTY);
313             if (eqn == 0) {
314                     solEqB = fill(1, 1, EMPTY);
315             } else {
316                     solEqB = fill(eqn, 1, EMPTY);
317             }
318         
319         omxProcessConstraintsCsolnp(&solIneqLB, &solIneqUB, &solEqB);
320
321         if (verbose == 2) {
322             mxLog("solIneqLB is: ");
323             for (int i = 0; i < solIneqLB.cols; i++){mxLog("%f", solIneqLB.t[i]);}
324             mxLog("solIneqUB is: ");
325             for (int i = 0; i < solIneqUB.cols; i++){mxLog("%f", solIneqUB.t[i]);}
326             mxLog("solEqB is: ");
327             for (int i = 0; i < solEqB.cols; i++){mxLog("%f", solEqB.t[i]);}
328         }
329         
330     }
331     omxSetupBoundsAndConstraints(freeVarGroup, bl, bu);
332     
333     Matrix blvar = fillMatrix(n, 1, bl);
334     Matrix buvar = fillMatrix(n, 1, bu);
335         
336     /* Initialize Starting Values */
337     if(OMX_VERBOSE) {
338         mxLog("--------------------------");
339         mxLog("Starting Values (%d) are:", n);
340     }
341     for(k = 0; k < n; k++) {
342         if((M(myPars, k, 0) == 0.0)) {
343             M(myPars, k, 0) += 0.1;
344         }
345         if(OMX_VERBOSE) { mxLog("%d: %.8f", k, M(myPars, k, 0)); }
346     }
347
348     if(OMX_DEBUG) {
349         mxLog("--------------------------");
350         mxLog("Setting up optimizer...");
351     }
352         
353     
354     p_obj = solnp(myPars, solFun, solEqB, solEqBFun, solIneqFun, blvar, buvar, solIneqUB, solIneqLB, myControl, myDEBUG, verbose);
355     
356     
357     fc->fit = p_obj.objValue;
358     if (verbose >= 1) {
359             mxLog("final objective value is: \n");
360             mxLog("%2f", fc->fit);
361     }
362     param_hess = p_obj.parameter;
363     
364     int i;
365     myPars = subset(param_hess, 0, 0, n-1);
366     
367     if (verbose>= 1){
368             mxLog("final myPars value is: \n");
369         for (i = 0; i < myPars.cols; i++) mxLog("%f", myPars.t[i]);
370     }
371     myhess = subset(param_hess, 0, n, param_hess.cols - myPars.cols - 2);
372     
373     Matrix inform_m = subset(param_hess, 0, param_hess.cols-1, param_hess.cols-1);
374     
375     inform = M(inform_m, 0, 0);
376     
377     if (verbose >= 2){
378             mxLog("myhess is: \n");
379         for (i = 0; i < myhess.cols; i++)
380             mxLog("%f", myhess.t[i]);
381     }
382     
383     mygrad = subset(param_hess, 0, myPars.cols + (myPars.cols*myPars.cols), param_hess.cols-2);
384     
385     for (i = 0; i < myPars.cols * myPars.cols; i++){
386         hessOut[i] = myhess.t[i];
387     }
388     
389     for (i = 0; i < myPars.cols; i++){
390         x[i] = myPars.t[i];
391         g[i] = mygrad.t[i];
392     }
393     
394     GLOB_fc->copyParamToModel(globalState);
395     
396     *inform_out = inform;
397     
398     GLOB_fitMatrix = NULL;
399     GLOB_fc = NULL;
400     freeMatrices();
401 }
402
403
404
405 // Mostly duplicated code in omxNPSOLConfidenceIntervals
406 // needs to be refactored so there is only 1 copy of CI
407 // code that can use whatever optimizer is provided.
408 void omxCSOLNPConfidenceIntervals(omxMatrix *fitMatrix, FitContext *fc, int verbose, double tolerance)
409 {
410         int ciMaxIterations = Global->ciMaxIterations;
411         // Will fail if we re-enter after an exception
412         //if (NPSOL_fitMatrix) Rf_error("NPSOL is not reentrant");
413     
414     GLOB_fitMatrix = fitMatrix;
415         GLOB_fc = fc;
416     
417         FreeVarGroup *freeVarGroup = fc->varGroup;
418     
419     int inform;
420     
421     int n = int(freeVarGroup->vars.size());
422     int ncnln = globalState->ncnln;
423     
424     double optimum = fc->fit;
425     
426     double *optimalValues = fc->est;
427     
428     double f = optimum;
429     std::vector< double > x(n, *optimalValues);
430     std::vector< double > gradient(n);
431     std::vector< double > hessian(n * n);
432     
433     /* CSOLNP Arguments */
434     double EMPTY = -999999.0;
435     
436     Param_Obj p_obj_conf;
437     Matrix param_hess;
438     Matrix myhess = fill(n*n, 1, (double)0.0);
439     Matrix mygrad;
440     Matrix solIneqLB;
441     Matrix solIneqUB;
442     Matrix solEqB;
443     
444     Matrix myPars = fillMatrix(n, 1, fc->est);
445     double (*solFun)(struct Matrix myPars, int verbose);
446     solFun = &csolnpLimitObjectiveFunction;
447     Matrix (*solEqBFun)(int verbose);
448     solEqBFun = &csolnpEqualityFunction;
449     Matrix (*solIneqFun)(int verbose);
450     solIneqFun = &csolnpIneqFun;
451     
452     
453     /* Set boundaries and widths. */
454     /* Allocate arrays */
455     std::vector<double> blBuf(n+ncnln);
456     std::vector<double> buBuf(n+ncnln);
457     double *bl = blBuf.data();
458     double *bu = buBuf.data();
459     
460     
461     struct Matrix myControl = fill(6,1,(double)0.0);
462     M(myControl,0,0) = 1.0;
463     M(myControl,1,0) = 400.0;
464     M(myControl,2,0) = 800.0;
465     M(myControl,3,0) = 1.0e-7;
466     M(myControl,4,0) = std::isfinite(tolerance)? tolerance : 1.0e-16;
467     M(myControl,5,0) = 0.0;
468     
469     bool myDEBUG = false;
470     /* Set up actual run */
471     
472     /* needs treatment*/
473     if (ncnln == 0)
474     {
475         solIneqLB = fill(1, 1, EMPTY);
476         solIneqUB = fill(1, 1, EMPTY);
477         solEqB = fill(1, 1, EMPTY);
478     }
479     else{
480         int j;
481         int nineqn;
482         int eqn = 0;
483         for(j = 0; j < globalState->numConstraints; j++) {
484             if (globalState->conList[j].opCode == 1)
485             {
486                 eqn += globalState->conList[j].size;
487             }
488         }
489         if (eqn == ncnln) nineqn = 1;
490         else nineqn = ncnln - eqn;
491         
492         solIneqLB = fill(nineqn, 1, EMPTY);
493         solIneqUB = fill(nineqn, 1, EMPTY);
494             if (eqn == 0) {
495                     solEqB = fill(1, 1, EMPTY);
496             } else {
497                     solEqB = fill(eqn, 1, EMPTY);
498             }
499         
500         omxProcessConstraintsCsolnp(&solIneqLB, &solIneqUB, &solEqB);
501         if (verbose == 2) {
502             printf("solIneqLB is: ");
503             print(solIneqLB); putchar('\n');
504             printf("solIneqUB is: ");
505             print(solIneqUB); putchar('\n');
506             printf("solEqB is: ");
507             print(solEqB); putchar('\n');
508         }
509     }
510     
511     omxSetupBoundsAndConstraints(freeVarGroup, bl, bu);
512     Matrix blvar = fillMatrix(n, 1, bl);
513     Matrix buvar = fillMatrix(n, 1, bu);
514     
515     if(OMX_DEBUG) { mxLog("Calculating likelihood-based confidence intervals."); }
516     
517     
518     if(OMX_DEBUG) { mxLog("Calculating likelihood-based confidence intervals.");
519         mxLog("numIntervals is: %d", Global->numIntervals);
520     }
521     
522     const double objDiff = 1.e-4;     // TODO : Use function precision to determine CI jitter?
523
524     for(int i = 0; i < Global->numIntervals; i++) {
525         omxConfidenceInterval *currentCI = &(Global->intervalList[i]);
526         
527         const char *matName = anonMatrix;
528         if (currentCI->matrix->name) {
529                 matName = currentCI->matrix->name;
530         }
531
532         Global->checkpointMessage(fc, fc->est, "%s[%d, %d] begin lower interval",
533                                   matName, currentCI->row + 1, currentCI->col + 1);
534         
535         memcpy(x.data(), optimalValues, n * sizeof(double)); // Reset to previous optimum
536         myPars = fillMatrix(n, 1, x.data());
537         CSOLNP_currentInterval = i;
538         
539         
540         currentCI->lbound += optimum;          // Convert from offsets to targets
541         currentCI->ubound += optimum;          // Convert from offsets to targets
542         
543         if (std::isfinite(currentCI->lbound))
544             {
545                 /* Set up for the lower bound */
546                 inform = -1;
547                 // Number of times to keep trying.
548                 int cycles = ciMaxIterations;
549         
550                 double value = INF;
551         
552                 while(inform!= 0 && cycles > 0) {
553                     /* Find lower limit */
554                     currentCI->calcLower = TRUE;
555                     p_obj_conf = solnp(myPars, solFun, solEqB, solEqBFun, solIneqFun, blvar, buvar, solIneqUB, solIneqLB, myControl, myDEBUG, verbose);
556             
557                     f = p_obj_conf.objValue;
558                         
559                     myPars = subset(p_obj_conf.parameter, 0, 0, n-1);
560                     myhess = subset(p_obj_conf.parameter, 0, n, p_obj_conf.parameter.cols - myPars.cols - 2);
561             
562                     mygrad = subset(p_obj_conf.parameter, 0, myPars.cols + (myPars.cols*myPars.cols), p_obj_conf.parameter.cols-2);
563             
564             
565                     Matrix inform_m = subset(p_obj_conf.parameter, 0, p_obj_conf.parameter.cols-1, p_obj_conf.parameter.cols-1);
566             
567                     inform = M(inform_m, 0, 0);
568             
569                     if(verbose>=1) { mxLog("inform_lower is: %d", inform);}
570                     
571                     currentCI->lCode = inform;
572             
573                     if(f < value) {
574                         currentCI->min = omxMatrixElement(currentCI->matrix, currentCI->row, currentCI->col);
575                 
576                         value = f;
577                         for (int ii = 0; ii < myPars.cols; ii++){
578                             x.data()[ii] = myPars.t[ii];
579                         }
580                     }
581             
582                     if(inform != 0 && OMX_DEBUG) {
583                         mxLog("Calculation of lower interval %d failed: Bad inform value of %d",
584                               i, inform);
585                     }
586                     cycles--;
587                     if(inform != 0) {
588                         unsigned int jitter = TRUE;
589                         for(int j = 0; j < n; j++) {
590                             if(fabs(x[j] - optimalValues[j]) > objDiff) {
591                                 jitter = FALSE;
592                                 if(OMX_DEBUG) {mxLog("are u here?????");}
593                                 break;
594                             }
595                         }
596                         if(jitter) {
597                             for(int j = 0; j < n; j++) {
598                                 x[j] = optimalValues[j] + objDiff;
599                             }
600                         }
601                     }
602                 }
603             }
604         
605         if (std::isfinite(currentCI->ubound)) {
606             currentCI->calcLower = FALSE;
607         Global->checkpointMessage(fc, fc->est, "%s[%d, %d] begin upper interval",
608                                   matName, currentCI->row + 1, currentCI->col + 1);
609
610         
611         memcpy(x.data(), optimalValues, n * sizeof(double));
612         myPars = fillMatrix(n, 1, x.data());
613         
614         
615         /* Reset for the upper bound */
616         double value = INF;
617         inform = -1;
618         int cycles = ciMaxIterations;
619
620         while(inform != 0 && cycles >= 0) {
621             /* Find upper limit */
622             currentCI->calcLower = FALSE;
623             p_obj_conf = solnp(myPars, solFun, solEqB, solEqBFun, solIneqFun, blvar, buvar, solIneqUB, solIneqLB, myControl, myDEBUG, verbose);
624             
625             f = p_obj_conf.objValue;
626             
627             myPars = subset(p_obj_conf.parameter, 0, 0, n-1);
628             myhess = subset(p_obj_conf.parameter, 0, n, p_obj_conf.parameter.cols - myPars.cols - 2);
629             
630             mygrad = subset(p_obj_conf.parameter, 0, myPars.cols + (myPars.cols*myPars.cols), p_obj_conf.parameter.cols-2);
631             
632             Matrix inform_m = subset(p_obj_conf.parameter, 0, p_obj_conf.parameter.cols-1, p_obj_conf.parameter.cols-1);
633             
634             
635             inform = M(inform_m, 0, 0);
636             if(verbose >= 1) { mxLog("inform_upper is: %d", inform);}
637             currentCI->uCode = inform;
638             
639             if(f < value) {
640                 currentCI->max = omxMatrixElement(currentCI->matrix, currentCI->row, currentCI->col);
641                 
642                 value = f;
643                                 for (int ii = 0; ii < myPars.cols; ii++){
644                                 x.data()[ii] = myPars.t[ii];
645                 }
646             }
647             
648             if(inform != 0 && OMX_DEBUG) {
649                 mxLog("Calculation of upper interval %d failed: Bad inform value of %d",
650                       i, inform);
651             }
652             cycles--;
653             if(inform != 0) {
654                 unsigned int jitter = TRUE;
655                 for(int j = 0; j < n; j++) {
656                     if(fabs(x[j] - optimalValues[j]) > objDiff){
657                         jitter = FALSE;
658                         break;
659                     }
660                 }
661                 if(jitter) {
662                     for(int j = 0; j < n; j++) {
663                         x[j] = optimalValues[j] + objDiff;
664                     }
665                 }
666             }
667         }
668         
669         if(OMX_DEBUG) {mxLog("Found Upper bound %d.", i);}
670         
671     }
672     }
673     
674         GLOB_fc = NULL;
675         GLOB_fitMatrix = NULL;
676         CSOLNP_currentInterval = -1;
677     freeMatrices();
678 }