Actual source code: tao.c

  1: /*$Id: tao.c 1.211 05/05/10 15:21:38-05:00 sarich@zorak.(none) $*/

  3: #include "src/tao_impl.h"      /*I "tao_solver.h"  I*/


  8: /*@C
  9:   TaoMonitor - Monitor the solver and the current solution.  This
 10:   routine will calls the records the iteration number and residual statistics,
 11:   monitors specified by the user, and calls the termaination routine.

 13:    Input Parameters:
 14: +  tao - the TAO_SOLVER context
 15: .  f - the current objective function value
 16: .  iterate - the current iterate number (>=0)
 17: .  fnorm - the gradient norm, square root of the duality gap, or other measure
 18: indicating distince from optimality.  This measure will be recorded and
 19: used for some termination tests.
 20: .  cnorm - the infeasibility of the current solution with regard to the constraints.
 21: -  step - multiple of the step direction added to the previous iterate.

 23:    Output Parameters:
 24: .  reason - The termination reason, which can equal TAO_CONTINUE_ITERATING

 26:    Options Database Key:
 27: .  -tao_monitor - The default monitor, which prints statistics to standard output is used.

 29: .seealso TaoGetTerminationReason(),TaoGetSolutionStatus()

 31:    Level: developer

 33: .keywords: Monitor, convergence
 34: @*/
 35: int TaoMonitor(TAO_SOLVER tao, int iterate, double f, double fnorm, double cnorm, double step, TaoTerminateReason *reason)
 36: {
 37:   int        i,info;
 38:   TaoTruth cstop;
 39:   TaoFunctionBegin;
 40:   if (iterate>=tao->iter){
 41:     TaoLogConvHistory(tao,fnorm,tao->iter);
 42:     tao->norm=fnorm; tao->cnorm=cnorm; tao->fc=f;
 43:     tao->iter=TaoMax(tao->iter,iterate);
 44:     tao->step=step;
 45:   }
 46:   if (iterate==0){
 47:     tao->norm0=fnorm; tao->cnorm0=cnorm;
 48:   }
 49:   info=TaoCheckConvergence(tao,&tao->reason);CHKERRQ(info);
 50:   if (iterate>0){
 51:     info=tao->taoappl->Monitor2(tao->vec_sol,tao->vec_grad,tao->vec_sol_update,&cstop);CHKERRQ(info);
 52:     if (cstop==TAO_TRUE) tao->reason=TAO_CONVERGED_USER;
 53:   }
 54:   for ( i=0; i<tao->numbermonitors; i++ ) {
 55:     info = (*tao->monitor[i])(tao,tao->monitorcontext[i]);CHKERRQ(info);
 56:   }
 57:   info=tao->taoappl->Monitor();CHKERRQ(info);
 58:   *reason = tao->reason;

 60:   TaoFunctionReturn(0);
 61: }


 66: /*@C
 67:   TaoGetSolutionStatus - Get the current iterate, objective value, residual, 
 68:   infeasibility, and termination 

 70:    Input Parameters:
 71: .  tao - the TAO_SOLVER context

 73:    Output Parameters:
 74: +  iterate - the current iterate number (>=0)
 75: .  f - the current function value
 76: .  gnorm - the square of the gradient norm, duality gap, or other measure
 77: indicating distince from optimality.
 78: .  cnorm - the infeasibility of the current solution with regard to the constraints.
 79: .  xdiff - the step length or trust region radius of the most recent iterate.
 80: -  reason - The termination reason, which can equal TAO_CONTINUE_ITERATING

 82:    Level: intermediate

 84:    Note:
 85:    TAO returns the values set by the solvers in the routine TaoMonitor().

 87:    Note:
 88:    If any of the output arguments are set to TAO_NULL, no value will be 
 89:    returned.


 92: .seealso: TaoMonitor(), TaoGetTerminationReason()

 94: .keywords: convergence, monitor
 95: @*/
 96: int TaoGetSolutionStatus(TAO_SOLVER tao, int* iterate, double* f, double* gnorm, double *cnorm, double *xdiff, TaoTerminateReason *reason)
 97: {

 99:   TaoFunctionBegin;
100:   if (iterate) *iterate=tao->iter;
101:   if (f) *f=tao->fc;
102:   if (gnorm) *gnorm=tao->norm;
103:   if (cnorm) *cnorm=tao->cnorm;
104:   if (reason) *reason=tao->reason;
105:   if (xdiff) *xdiff=tao->step;

107:   TaoFunctionReturn(0);
108: }


113: /*@C

115:    TaoCheckConvergence - Checks the convergence of the solver

117:    Collective on TAO_SOLVER

119:    Input Parameters:
120: .  tao - the TAO_SOLVER context

122:    Output Parameters:
123: .  reason - one of

125: $    TAO_CONVERGED_ATOL (2),        (res <= atol)  
126: $    TAO_CONVERGED_RTOL (3),        (res/res0 <= rtol) 
127: $    TAO_CONVERGED_TRTOL (4),       (xdiff <= trtol) 
128: $    TAO_CONVERGED_MINF (5),        (f <= fmin)
129: $    TAO_CONVERGED_USER (6),        (user defined)

131: $    TAO_DIVERGED_MAXITS (-2),      (its>maxits)
132: $    TAO_DIVERGED_NAN (-4),         (Numerical problems)
133: $    TAO_DIVERGED_MAXFCN (-5),      (nfunc > maxnfuncts)
134: $    TAO_DIVERGED_LS_FAILURE (-6),  (line search failure)
135: $    TAO_DIVERGED_TR_REDUCTION (-7),
136: $    TAO_DIVERGED_USER (-8),        (user defined)

138: $    TAO_CONTINUE_ITERATING  (0)

140:    where
141: +  res - residual of optimality conditions
142: .  res0 - initial residual of optimality conditions
143: .  xdiff - current trust region size
144: .  f - function value
145: .  atol - absolute tolerance
146: .  rtol - relative tolerance
147: .  its - current iterate number
148: .  maxits - maximum number of iterates
149: .  nfunc - number of function evaluations
150: -  maxnfuncts - maximum number of function evaluations


153:    Level: advanced

155: .seealso: TaoGetTerminationReason()

157: .keywords: Convergence

159: @*/
160: int TaoCheckConvergence(TAO_SOLVER tao, TaoTerminateReason *reason)
161: {
162:   int        info;

164:   TaoFunctionBegin;
165:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
166:   if (tao->converged){
167:     info = (*tao->converged)(tao,tao->cnvP);CHKERRQ(info);
168:   }
169:   if (reason) *reason=tao->reason;

171:   TaoFunctionReturn(0);
172: }

176: /*@ 
177:    TaoView - Prints the TAO_SOLVER data structure.

179:    Collective on TAO_SOLVER

181:    Input Parameters:
182: .  tao - the TAO_SOLVER context

184:    Options Database Key:
185: .  -tao_view - Calls TaoView() at end of TaoSolve()

187:    Level: beginner

189: .seealso: TaoGetTerminationReason(), TaoGetSolutionStatus(), TaoViewLinearSolver()

191: .keywords: View

193: @*/
194: int TaoView(TAO_SOLVER tao)
195: {
196:   int        info;
197:   TaoMethod  type;

199:   TaoFunctionBegin;
200:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);

202:   info = TaoPrintStatement(tao,"TAO_SOLVER:\n");CHKERRQ(info);
203:   info = TaoGetMethod(tao,&type);CHKERRQ(info);
204:   if (type) {
205:     info = TaoPrintString(tao,"  method: %s\n",type);CHKERRQ(info);
206:   } else {
207:     info = TaoPrintStatement(tao,"  method: not set yet\n");CHKERRQ(info);
208:   }
209:   if (tao->view) {
210:     info = (*tao->view)(tao,tao->data);CHKERRQ(info);
211:   }
212:   if (tao->lm>0){
213:     info = TaoPrintInt(tao,"  Limited memory variable metric vectors =%d\n",tao->lm);CHKERRQ(info);
214:   }
215: 
216:   info=TaoPrintDouble(tao,"  convergence tolerances: fatol=%g,",tao->fatol);CHKERRQ(info);
217:   info=TaoPrintDouble(tao," frtol=%g\n",tao->frtol);CHKERRQ(info);

219:   info=TaoPrintDouble(tao,"  convergence tolerances: gatol=%g,",tao->gatol);CHKERRQ(info);
220:   info=TaoPrintDouble(tao," trtol=%g,",tao->trtol);CHKERRQ(info);
221:   info=TaoPrintDouble(tao," gttol=%g\n",tao->gttol);CHKERRQ(info);

223:   info = TaoPrintDouble(tao,"  Residual in Function/Gradient:=%e\n",tao->norm);CHKERRQ(info);

225:   if (tao->cnorm>0 || tao->catol>0 || tao->crtol>0){
226:     info=TaoPrintStatement(tao,"  convergence tolerances:");CHKERRQ(info);
227:     info=TaoPrintDouble(tao," catol=%g,",tao->catol);CHKERRQ(info);
228:     info=TaoPrintDouble(tao," crtol=%g\n",tao->crtol);CHKERRQ(info);
229:     info = TaoPrintDouble(tao,"  Residual in Constraints:=%e\n",tao->cnorm);CHKERRQ(info);
230:   }

232:   if (tao->trtol>0){
233:     info=TaoPrintDouble(tao,"  convergence tolerances: trtol=%g\n",tao->trtol);CHKERRQ(info);
234:     info=TaoPrintDouble(tao,"  Final step size/trust region radius:=%g\n",tao->step);CHKERRQ(info);
235:   }

237:   if (tao->fmin>-1.e25){
238:     info=TaoPrintDouble(tao,"  convergence tolerances: function minimum=%g\n",tao->fmin);CHKERRQ(info);
239:   }
240:   info = TaoPrintDouble(tao,"  Objective value=%e\n",tao->fc);CHKERRQ(info);

242:   info = TaoPrintInt(tao,"  total number of iterations=%d,          ",tao->iter);CHKERRQ(info);
243:   info = TaoPrintInt(tao,"              (max: %d)\n",tao->max_its);CHKERRQ(info);

245:   if (tao->nfuncs>0){
246:     info = TaoPrintInt(tao,"  total number of function evaluations=%d,",tao->nfuncs);CHKERRQ(info);
247:     info = TaoPrintInt(tao,"                max: %d\n",tao->max_funcs);CHKERRQ(info);
248:   }
249:   if (tao->ngrads>0){
250:     info = TaoPrintInt(tao,"  total number of function/gradient evaluations=%d,",tao->ngrads);CHKERRQ(info);
251:     info = TaoPrintInt(tao,"    (max: %d)\n",tao->max_funcs);CHKERRQ(info);
252:   }
253:   if (tao->linear_its>0){
254:     info = TaoPrintInt(tao,"  total Krylov method iterations=%d\n",tao->linear_its);CHKERRQ(info);
255:   }
256:   if (tao->nhesss>0){
257:     info = TaoPrintInt(tao,"  total number of Hessian evaluations=%d\n",tao->nhesss);CHKERRQ(info);
258:   }
259:   if (tao->nvfunc>0){
260:     info = TaoPrintInt(tao,"  total number of constraint function evaluations=%d\n",tao->nvfunc);CHKERRQ(info);
261:   }
262:   if (tao->njac>0){
263:     info = TaoPrintInt(tao,"  total number of Jacobian evaluations=%d\n",tao->njac);CHKERRQ(info);
264:   }

266:   if (tao->reason>0){
267:     info = TaoPrintStatement(tao,"  Solution found\n");CHKERRQ(info);
268:   } else {
269:     info = TaoPrintInt(tao,"  Solver terminated: %d\n",tao->reason);CHKERRQ(info);
270:   }

272:   TaoFunctionReturn(0);
273: }



277: /* ----------- Routines to set solver parameters ---------- */

281: /*@
282:    TaoSetGradientTolerances - Sets the stopping criteria in terms of the norm
283:    of the Lagrangian function.  The algorithm will terminate when the norm
284:    of the gradient is less that the absolute tolerance, or when the norm
285:    of the gradient has been reduced by a factor of the reduction tolerance, 
286:    or when the norm of the gradient divided by the absolute value of the 
287:    objective function is less than the relative tolerance.

289:    Collective on TAO_SOLVER

291:    Input Parameters:
292: +  tao - the TAO_SOLVER solver context
293: .  gatol - stop if norm of gradient is less than 
294: .  grtol - stop if relative norm of gradient is less than
295: -  gttol - stop if norm of gradient is reduced by a factor of

297:    Options Database Keys: 
298: +  -tao_gatol <gatol> - sets gatol
299: .  -tao_grtol <grtol> - sets grtol
300: -  -tao_gttol <gttol> - sets gttol

302:    Level: intermediate

304: .keywords: Gradient, options, convergence

306: .seealso: TaoSetTolerances(), TaoGetGradientTolerances()
307: @*/
308: int TaoSetGradientTolerances(TAO_SOLVER tao,double gatol, double grtol, double gttol)
309: {
310:   int info;
311:   double zero=0.0;
312:   TaoFunctionBegin;
313:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);

315:   if (gatol==TAO_DEFAULT){}
316:   else if (gatol<0){
317:     info=PetscLogInfo((tao,"Absolute Gradient tolerance < 0 and ignored")); CHKERRQ(info);
318:     CHKERRQ(info); }
319:   else{
320:     tao->gatol      = TaoMax(zero,gatol);
321:   }

323:   if (grtol==TAO_DEFAULT){}
324:   else if (grtol<0){
325:     info=PetscLogInfo((tao,"Relative Gradient tolerance < 0 and ignored"));
326:     CHKERRQ(info); }
327:   else{
328:     tao->grtol      = TaoMax(zero,grtol);
329:   }

331:   if (gttol==TAO_DEFAULT){}
332:   else if (gttol<0){
333:     info=PetscLogInfo((tao,"Gradient reduction tolerance < 0 and ignored"));
334:     CHKERRQ(info); }
335:   else{
336:     tao->gttol      = TaoMax(zero,gttol);
337:   }


340:   TaoFunctionReturn(0);
341: }

343: /* ----------- Routines to set solver parameters ---------- */

347: /*@C
348:    TaoGetGradientTolerances - Returns the gradient termination tolerances.

350:    Collective on TAO_SOLVER

352:    Input Parameters:
353: .  tao - the TAO_SOLVER tao context

355:    Output Parameters:
356: +  gatol - the absolute gradient tolerance
357: .  grtol - the relative gradient tolerance
358: -  gttol - the gradient reduction tolerance

360:    Level: intermediate

362: .keywords: options, convergence, View

364: .seealso: TaoSetGradientTolerances()
365: @*/
366: int TaoGetGradientTolerances(TAO_SOLVER tao,double *gatol, double *grtol, double *gttol)
367: {
368:   TaoFunctionBegin;
369:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
370:   if (gatol) *gatol = tao->gatol;
371:   if (grtol) *grtol = tao->grtol;
372:   if (gttol) *gttol = tao->gttol;
373:   TaoFunctionReturn(0);
374: }

378: /*@
379:    TaoSetFunctionLowerBound - Sets a bound on the solution objective value.
380:    When an approximate solution with an objective value below this number
381:    has been found, the solver will terminate.

383:    Collective on TAO_SOLVER

385:    Input Parameters:
386: +  tao - the TAO_SOLVER solver context
387: -  fmin - the tolerance

389:    Options Database Keys: 
390: .    -tao_fmin <fmin> - sets the minimum function value

392:    Level: intermediate

394: .keywords: options, View, Bounds,

396: .seealso: TaoSetTolerances()
397: @*/
398: int TaoSetFunctionLowerBound(TAO_SOLVER tao,double fmin)
399: {
400:   double dflt=-1.0e+30;
401:   TaoFunctionBegin;
402:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
403:   if (fmin != TAO_DEFAULT)  tao->fmin = fmin;
404:   else tao->fmin=dflt;
405:   TaoFunctionReturn(0);
406: }


411: /*@
412:    TaoSetMaximumIterates - Sets a maximum number of iterates.

414:    Collective on TAO_SOLVER

416:    Input Parameters:
417: +  tao - the TAO_SOLVER solver context
418: -  maxits - the maximum number of iterates (>=0)

420:    Options Database Keys: 
421: .    -tao_max_it <its> - sets the maximum number of iterations

423:    Level: intermediate

425: .keywords: options, Iterate, convergence

427: .seealso: TaoSetTolerances(), TaoSetMaximumFunctionEvaluations()
428: @*/
429: int TaoSetMaximumIterates(TAO_SOLVER tao,int maxits)
430: {
431:   int zero=0;
432:   TaoFunctionBegin;
433:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
434:   if (maxits != TAO_DEFAULT)  tao->max_its = TaoMax(zero,maxits);
435:   TaoFunctionReturn(0);
436: }


441: /*@
442:    TaoSetMaximumFunctionEvaluations - Sets a maximum number of 
443:    function evaluations.

445:    Collective on TAO_SOLVER

447:    Input Parameters:
448: +  tao - the TAO_SOLVER solver context
449: -  nfcn - the maximum number of function evaluations (>=0)

451:    Options Database Keys: 
452: .    -tao_max_funcs <nfcn> - sets the maximum number of function evaluations

454:    Level: intermediate

456: .keywords: options, Iterate,  convergence

458: .seealso: TaoSetTolerances(), TaoSetMaximumIterates()
459: @*/
460: int TaoSetMaximumFunctionEvaluations(TAO_SOLVER tao,int nfcn)
461: {
462:   int zero=0;
463:   TaoFunctionBegin;
464:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
465:   if (nfcn != TAO_DEFAULT)  tao->max_funcs = TaoMax(zero,nfcn);
466:   TaoFunctionReturn(0);
467: }


472: /*@
473:    TaoSetTolerances - Sets convergence parameters. TAO tries to satisfy an
474:    absolute stopping criteria or a relative stopping criteria.
475:    
476:    Collective on TAO_SOLVER

478:    Input Parameters:
479: +  tao - the TAO_SOLVER solver context
480: .  fatol - absolute convergence tolerance
481: .  frtol - relative convergence tolerance
482: .  catol -  allowable error in constraints
483: -  crtol - allowable relative error in constraints

485:    Options Database Keys: 
486: +  -tao_fatol <fatol> - Sets fatol
487: .  -tao_frtol <frtol> - Sets frtol
488: .  -tao_catol <catol> - Sets catol
489: -  -tao_crtol <crtol> - Sets crtol

491:    Absolute Stopping Criteria:
492: $  f <= f + fatol
493: $  B1 - catol <= B(X) <= B2 + catol

495:    Relative stopping criteria:
496: $  f <= f + frtol*|f|
497: $  B1 - catol <= B(X) <= B2 + catol

499:    Level: beginner

501: .keywords: options, convergence

503: .seealso: TaoSetMaximumIterates(),TaoSetTrustRegionTolerance(), TaoSetGradientTolerances
504: TaoSetMaximumFunctionEvaluations()
505: @*/
506: int TaoSetTolerances(TAO_SOLVER tao,double fatol,double frtol,double catol,double crtol)
507: {
508:   int info;
509:   double zero=0.0;
510:   TaoFunctionBegin;
511:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);

513:   if (fatol==TAO_DEFAULT){}
514:   else if (fatol<0){
515:     info=PetscLogInfo((tao,"Absolute convergence tolerance < 0 and ignored"));
516:     CHKERRQ(info); }
517:   else{
518:     tao->fatol      = TaoMax(zero,fatol);
519:   }

521:   if (frtol==TAO_DEFAULT){}
522:   else if (frtol<0){
523:     info=PetscLogInfo((tao,"Relative convergence tolerance < 0 and ignored"));
524:     CHKERRQ(info); }
525:   else{
526:     tao->frtol      = TaoMax(zero,frtol);
527:   }

529:   if (catol==TAO_DEFAULT){}
530:   else if (catol<0){
531:     info=PetscLogInfo((tao,"Absolute constraint tolerance < 0 and ignored"));
532:     CHKERRQ(info); }
533:   else{
534:     tao->catol      = TaoMax(zero,catol);
535:   }

537:   if (crtol==TAO_DEFAULT){}
538:   else if (crtol<0){
539:     info=PetscLogInfo((tao,"Relative constraint tolerance < 0 and ignored"));
540:     CHKERRQ(info); }
541:   else{
542:     tao->crtol      = TaoMax(zero,crtol);
543:   }

545:   TaoFunctionReturn(0);
546: }



552: /*@C
553:    TaoGetTolerances - Gets convergence parameters.
554:    

556:    Collective on TAO_SOLVER

558:    Input Parameters:
559: .  tao - the TAO_SOLVER solver context

561:    Input Parameters:
562: +  fatol - absolute convergence tolerance
563: .  frtol - relative convergence tolerance
564: .  catol -  trust region convergence tolerance
565: -  crtol - convergence of the function evaluates less than this tolerance

567:    Level: advanced

569: .keywords: options, convergence

571: .seealso: TaoSetTolerances
572: @*/
573: int TaoGetTolerances(TAO_SOLVER tao,double *fatol,double *frtol,double *catol,double *crtol)
574: {
575:   TaoFunctionBegin;
576:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
577:   if (fatol) *fatol = tao->fatol;
578:   if (frtol) *frtol = tao->frtol;
579:   if (catol) *catol = tao->catol;
580:   if (crtol) *crtol = tao->crtol;
581:   TaoFunctionReturn(0);
582: }


585: /* ------------ Routines to set performance monitoring options ----------- */

589: /*@C
590:    TaoSetMonitor - Sets an ADDITIONAL function that is to be used at every
591:    iteration of the unconstrained minimization solver to display the iteration's 
592:    progress.   

594:    Collective on TAO_SOLVER

596:    Input Parameters:
597: +  tao - the TAO_SOLVER solver context
598: .  mymonitor - monitoring routine
599: -  mctx - [optional] user-defined context for private data for the 
600:           monitor routine (may be TAO_NULL)

602:    Calling sequence of mymonitor:
603: $     int mymonitor(TAO_SOLVER tao,void *mctx)

605: +    tao - the TAO_SOLVER solver context
606: -    mctx - [optional] monitoring context


609:    Options Database Keys:
610: +    -tao_monitor        - sets TaoDefaultMonitor()
611: .    -tao_smonitor        - sets short monitor
612: -    -tao_cancelmonitors - cancels all monitors that have been hardwired into a code by calls to TaoSetMonitor(), but does not cancel those set via the options database.

614:    Notes: 
615:    Several different monitoring routines may be set by calling
616:    TaoSetMonitor() multiple times; all will be called in the 
617:    order in which they were set.

619:    Level: intermediate

621: .keywords: options, monitor, View

623: .seealso: TaoDefaultMonitor(), TaoClearMonitor(),  TaoSetDestroyRoutine()
624: @*/
625: int TaoSetMonitor(TAO_SOLVER tao,int (*mymonitor)(TAO_SOLVER,void*),void *mctx)
626: {
627:   TaoFunctionBegin;
628:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
629:   if (tao->numbermonitors >= MAX_TAO_MONITORS) {
630:     SETERRQ(1,"Too many monitors set");
631:   }

633:   tao->monitor[tao->numbermonitors]           = mymonitor;
634:   tao->monitorcontext[tao->numbermonitors++]  = (void*)mctx;
635:   TaoFunctionReturn(0);
636: }

640: /*@
641:    TaoClearMonitor - Clears all the monitor functions for a TAO_SOLVER object.

643:    Collective on TAO_SOLVER

645:    Input Parameters:
646: .  tao - the TAO_SOLVER solver context

648:    Options Database:
649: .  -tao_cancelmonitors - cancels all monitors that have been hardwired
650:     into a code by calls to TaoSetMonitor(), but does not cancel those 
651:     set via the options database

653:    Notes: 
654:    There is no way to clear one specific monitor from a TAO_SOLVER object.

656:    Level: advanced

658: .keywords: options, monitor, View

660: .seealso: TaoDefaultMonitor(), TaoSetMonitor()
661: @*/
662: int TaoClearMonitor(TAO_SOLVER tao)
663: {
664:   TaoFunctionBegin;
665:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
666:   tao->numbermonitors = 0;
667:   TaoFunctionReturn(0);
668: }

672: /*@C
673:    TaoSetConvergenceTest - Sets the function that is to be used 
674:    to test for convergence of the iterative minimization solution.   

676:    Collective on TAO_SOLVER

678:    Input Parameters:
679: +  tao - the TAO_SOLVER solver context
680: .  conv - routine to test for convergence
681: -  cctx - [optional] context for private data for the convergence routine 
682:           (may be TAO_NULL)

684:    Calling sequence of conv:
685: $     int conv (TAO_SOLVER tao, void *cctx)

687: +    tao - the TAO_SOLVER solver context
688: -    cctx - [optional] convergence context

690:    Note: This routine should call TaoSetTerminationReason().

692:    Level: intermediate

694: .keywords: options, convergence

696: .seealso: TaoSetTerminationReason(), TaoGetSolutionStatus(), TaoGetTolerances(),  TaoGetGradientTolerances()

698: @*/
699: int TaoSetConvergenceTest(TAO_SOLVER tao,int (*conv)(TAO_SOLVER,void*),void *cctx)
700: {
701:   TaoFunctionBegin;
702:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
703:   (tao)->converged = conv;
704:   (tao)->cnvP      = cctx;
705:   TaoFunctionReturn(0);
706: }


711: /*@C
712:    TaoGetTerminationReason - Gets the reason the TAO_SOLVER iteration was stopped.

714:    Not Collective

716:    Input Parameter:
717: .  tao - the TAO_SOLVER solver context

719:    Output Parameter:
720: .  reason - one of

722: $    TAO_CONVERGED_ATOL (2),        (res <= atol)  
723: $    TAO_CONVERGED_RTOL (3),        (res/res0 <= rtol) 
724: $    TAO_CONVERGED_TRTOL (4),       (xdiff <= trtol) 
725: $    TAO_CONVERGED_MINF (5),        (f <= fmin)
726: $    TAO_CONVERGED_USER (6),        (user defined)

728: $    TAO_DIVERGED_MAXITS (-2),      (its>maxits)
729: $    TAO_DIVERGED_NAN (-4),         (Numerical problems)
730: $    TAO_DIVERGED_MAXFCN (-5),      (nfunc > maxnfuncts)
731: $    TAO_DIVERGED_LS_FAILURE (-6),  (line search failure)
732: $    TAO_DIVERGED_TR_REDUCTION (-7),
733: $    TAO_DIVERGED_USER (-8),        (user defined)

735: $    TAO_CONTINUE_ITERATING  (0)

737:    where
738: +  res - residual of optimality conditions
739: .  res0 - initial residual of optimality conditions
740: .  xdiff - current trust region size
741: .  f - function value
742: .  atol - absolute tolerance
743: .  rtol - relative tolerance
744: .  its - current iterate number
745: .  maxits - maximum number of iterates
746: .  nfunc - number of function evaluations
747: -  maxnfuncts - maximum number of function evaluations

749:    Level: intermediate

751: .keywords: convergence, View

753: .seealso: TaoSetConvergenceTest(), TaoSetTolerances()
754: @*/
755: int TaoGetTerminationReason(TAO_SOLVER tao,TaoTerminateReason *reason)
756: {
757:   TaoFunctionBegin;
758:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
759:   *reason = tao->reason;
760:   TaoFunctionReturn(0);
761: }

765: /*@
766:    TaoSetConvergenceHistory - Sets the array used to hold the convergence history.

768:    Collective on TAO_SOLVER

770:    Input Parameters:
771: +  tao - the TAO_SOLVER solver context
772: .  a   - array to hold history
773: .  its - integer array holds the number of linear iterations (or
774:          negative if not converged) for each solve.
775: .  na  - size of a and its
776: -  reset - TAO_TRUE indicates each new minimization resets the history counter to zero,
777:            else it continues storing new values for new minimizations after the old ones

779:    Notes:
780:    If set, this array will contain the gradient norms computed at each step.

782:    This routine is useful, e.g., when running a code for purposes
783:    of accurate performance monitoring, when no I/O should be done
784:    during the section of code that is being timed.

786:    Level: intermediate

788: .keywords: options, view, monitor, convergence, history

790: .seealso: TaoGetConvergenceHistory()

792: @*/
793: int TaoSetConvergenceHistory(TAO_SOLVER tao, double *a, int *its,int na,TaoTruth reset)
794: {
795:   TaoFunctionBegin;
796:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
797:   if (na) TaoValidScalarPointer(a,2);
798:   tao->conv_hist       = a;
799:   tao->conv_hist_its   = its;
800:   tao->conv_hist_max   = na;
801:   tao->conv_hist_reset = reset;
802:   TaoFunctionReturn(0);
803: }

807: /*@C
808:    TaoGetConvergenceHistory - Gets the array used to hold the convergence history.

810:    Collective on TAO_SOLVER

812:    Input Parameter:
813: .  tao - the TAO_SOLVER solver context

815:    Output Parameters:
816: +  a   - array to hold history
817: .  its - integer array holds the number of linear iterations (or
818:          negative if not converged) for each solve.
819: -  na  - size of a and its

821:    Notes:
822:     The calling sequence for this routine in Fortran is
823: $   call TaoGetConvergenceHistory(TAO_SOLVER tao, integer na, integer info)

825:    This routine is useful, e.g., when running a code for purposes
826:    of accurate performance monitoring, when no I/O should be done
827:    during the section of code that is being timed.

829:    Level: advanced

831: .keywords: convergence, history, monitor, View

833: .seealso: TaoSetConvergencHistory()

835: @*/
836: int TaoGetConvergenceHistory(TAO_SOLVER tao, double **a, int **its,int *na)
837: {
838:   TaoFunctionBegin;
839:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
840:   if (a)   *a   = tao->conv_hist;
841:   if (its) *its = tao->conv_hist_its;
842:   if (na) *na   = tao->conv_hist_len;
843:   TaoFunctionReturn(0);
844: }


849: /*@
850:    TaoSolve - Solves an unconstrained minimization problem.  Call TaoSolve() 
851:    after calling TaoCreate() and optional routines of the form TaoSetXXX().

853:    Collective on TAO_SOLVER

855:    Input Parameters:
856: .  tao - the TAO_SOLVER solver context

858:    Notes:
859:    By default the TAO solvers use an initial starting guess of zero.  To
860:    provide an alternative initial guess, the user must call TaoAppSetInitialSolutionVec()
861:    before calling TaoSolve().

863:    Level: advanced

865: .keywords: Solve

867: .seealso: TaoCreate(), TaoDestroy()
868: @*/
869: int TaoSolve(TAO_SOLVER tao)
870: {
871:   int      info;
872:   TaoVec   *xx;

874:   TaoFunctionBegin;
875:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
876:   info = TaoGetSolution(tao,&xx);CHKERRQ(info);
877:   info = tao->taoappl->InitializeVariables(xx);CHKERRQ(info);
878:   info = TaoSetUp(tao);CHKERRQ(info);
879:   info = TaoSetDefaultStatistics(tao); CHKERRQ(info);
880:   if (tao->solve){ info = (*(tao)->solve)(tao,tao->data);CHKERRQ(info); }
881:   if (tao->viewtao) { info = TaoView(tao);CHKERRQ(info); }
882:   if (tao->viewksptao) { info = TaoViewLinearSolver(tao);CHKERRQ(info); }
883:   TaoFunctionReturn(0);
884: }


889: /*@C
890:    TaoGetMethod - Gets the TAO_SOLVER method type and name (as a string).

892:    Not Collective

894:    Input Parameter:
895: .  tao - the TAO_SOLVER solver context

897:    Output Parameter:
898: .  type - TAO_SOLVER method (a charactor string)

900:    Level: intermediate

902: .keywords: method
903: @*/
904: int TaoGetMethod(TAO_SOLVER tao, TaoMethod *type)
905: {
906:   TaoFunctionBegin;
907:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
908:   *type = tao->type_name;
909:   TaoFunctionReturn(0);
910: }


915: /*@C
916:    TaoSetStepDirectionVector - Sets the vector where the solution update is
917:    stored. 

919:    Not Collective, but Vec is parallel if TAO_SOLVER is parallel

921:    Input Parameter:
922: +  tao - the TAO_SOLVER solver context
923: -  dx - the step direction vector

925:    Level: developer

927: .keywords: solution, step direction

929: .seealso: TaoGetSolution(), TaoGetStepDirectionVector()
930: @*/
931: int TaoSetStepDirectionVector(TAO_SOLVER tao,TaoVec* dx)
932: {
933:   TaoFunctionBegin;
934:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
935:   tao->vec_sol_update=dx;
936:   TaoFunctionReturn(0);
937: }


942: /*@C
943:    TaoGetStepDirectionVector - Returns the vector where the solution update is
944:    stored. 

946:    Not Collective, but Vec is parallel if TAO_SOLVER is parallel

948:    Input Parameter:
949: .  tao - the TAO_SOLVER solver context

951:    Output Parameter:
952: .  xx - the solution update

954:    Level: developer

956: .keywords: solution

958: .seealso: TaoGetSolution()
959: @*/
960: int TaoGetStepDirectionVector(TAO_SOLVER tao,TaoVec** xx)
961: {
962:   TaoFunctionBegin;
963:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
964:   *xx = tao->vec_sol_update;
965:   TaoFunctionReturn(0);
966: }



972: /*@
973:   TaoSetTrustRegionTolerance - Sets a minimum step size or trust region radius.  The
974:   solver will terminate when the step size or radius of the trust region is smaller
975:   than this tolerance.
976:   
977:   Collective on TAO_SOLVER
978:   
979:   Input Parameters:
980: +  tao - the TAO_SOLVER solver context
981: -  steptol - tolerance
982:   
983:   Options Database Key: 
984: .  -tao_steptol <trtol> - Sets steptol
985:   
986:   Level: intermediate
987:   
988: .keywords: options, convergence, trust region
989:   
990: .seealso: TaoSetTolerances()
991: @*/
992: int TaoSetTrustRegionTolerance(TAO_SOLVER tao,double steptol)
993: {
994:   double zero=0.0, dflt=0.0;

996:   TaoFunctionBegin;
997:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
998:   if (steptol != TAO_DEFAULT)  tao->xtol = TaoMax(zero,steptol);
999:   else tao->xtol=dflt;
1000:   tao->trtol=steptol;
1001:   TaoFunctionReturn(0);
1002: }

1006: /*@C
1007:    TaoGetTrustRegionRadius - Gets the current trust region radius

1009:    Collective on TAO_SOLVER

1011:    Input Parameter:
1012: .  tao - a TAO optimization solver

1014:    Output Parameter:
1015: .  radius - the trust region radius

1017:    Level: advanced

1019: .keywords: options, view, trust region

1021: .seealso: TaoSetTrustRegionRadius(), TaoSetTrustRegionTolerance()
1022: @*/
1023: int TaoGetTrustRegionRadius(TAO_SOLVER tao,double *radius)
1024: {
1025:   TaoFunctionBegin;
1026:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
1027:   *radius=tao->step;
1028:   TaoFunctionReturn(0);
1029: }
1032: /*@C
1033:    TaoGetInitialTrustRegionRadius - Gets the initial trust region radius

1035:    Collective on TAO_SOLVER

1037:    Input Parameter:
1038: .  tao - a TAO optimization solver

1040:    Output Parameter:
1041: .  radius - the initial trust region radius

1043:    Level: intermediate

1045: .keywords: options, trust region

1047: .seealso: TaoGetTrustRegionRadius(), TaoSetTrustRegionRadius()
1048: @*/
1049: int TaoGetInitialTrustRegionRadius(TAO_SOLVER tao,double *radius)
1050: {
1051:   TaoFunctionBegin;
1052:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
1053:   *radius=tao->trust0;
1054:   TaoFunctionReturn(0);
1055: }

1059: /*@
1060:    TaoSetTrustRegionRadius - Sets the initial trust region radius.

1062:    Collective on TAO_SOLVER

1064:    Input Parameter:
1065: +  tao - a TAO optimization solver
1066: -  radius - the trust region radius

1068:    Level: intermediate

1070:    Options Database Key:
1071: .  -tao_trust0

1073: .keywords: trust region

1075: .seealso: TaoGetTrustRegionRadius(), TaoSetTrustRegionTolerance()
1076: @*/
1077: int TaoSetTrustRegionRadius(TAO_SOLVER tao,double radius)
1078: {
1079:   TaoFunctionBegin;
1080:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
1081:   tao->trust0=radius;
1082:   tao->step=radius;
1083:   TaoFunctionReturn(0);
1084: }


1089: /*@
1090:    TaoSetVariableBounds - Sets lower and upper bounds on the variables.

1092:    Collective on TAO_SOLVER

1094:    Input Parameters:
1095: +  tao - the TAO_SOLVER solver context
1096: .  xxll - vector of lower bounds upon the solution vector
1097: -  xxuu - vector of upper bounds upon the solution vector

1099:    Level: developer

1101: .keywords: bounds

1103: .seealso: TaoGetVariableBounds(), TaoAppSetVariableBounds()
1104: @*/
1105: int TaoSetVariableBounds(TAO_SOLVER tao,TaoVec *xxll,TaoVec *xxuu)
1106: {
1107:   int info;
1108:   double dd;
1109:   TaoVec *xx;
1110:   TaoTruth flag;

1112:   TaoFunctionBegin;
1113:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
1114:   info=TaoGetSolution(tao,&xx);CHKERRQ(info);
1115:   if (xxll){
1116:     info=xx->Compatible(xxll,&flag); CHKERRQ(info);
1117:     if (flag == TAO_FALSE){
1118:       SETERRQ(1,"Vector of lower bounds not Compatible with Variable Vector");
1119:     }
1120:     if (tao->XL==0){
1121:       dd=-TAO_INFINITY;
1122:       info = xxll->SetToConstant(dd); CHKERRQ(info);
1123:     }
1124:   }
1125:   if (xxuu){
1126:     info=xx->Compatible(xxuu,&flag); CHKERRQ(info);
1127:     if (flag == TAO_FALSE){
1128:       SETERRQ(1,"Vector of upper bounds not Compatible with Variable vector");
1129:     }
1130:     if (tao->XU==0){
1131:       dd= TAO_INFINITY;
1132:       info = xxuu->SetToConstant(dd); CHKERRQ(info);
1133:     }
1134:   }
1135:   tao->XL=xxll;
1136:   tao->XU=xxuu;
1137:   TaoFunctionReturn(0);
1138: }

1142: /*@C
1143:    TaoGetDualVariables - Gets the dual variables corresponding to
1144:    the bounds of the variables.

1146:    Collective on TAO_SOLVER

1148:    Input Parameter:
1149: +  tao - the TAO_SOLVER solver context
1150: .  DXL   - vector to place the dual variables of the lower bounds
1151: -  DXU   - vector to place the dual variables of the upper bounds

1153:    Output Parameter:
1154: +  DXL   - dual variables of the lower bounds
1155: -  DXU   - dual variables of the upper bounds

1157:    Level: advanced

1159: .keywords: dual, bounds

1161: .seealso: TaoGetVariableBounds()
1162: @*/
1163: int TaoGetDualVariables(TAO_SOLVER tao, TaoVec *DXL, TaoVec *DXU)
1164: {
1165:   int info;
1166:   TaoTruth flag;
1167:   TaoVec *XL, *XU;

1169:   TaoFunctionBegin;
1170:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
1171:   info=TaoGetVariableBounds(tao,&XL,&XU);CHKERRQ(info);

1173:   info=DXU->Compatible(XU,&flag); CHKERRQ(info);
1174:   if (flag == TAO_FALSE){
1175:     SETERRQ(1,"Dual bound vectors not Compatible");
1176:   }

1178:   info=DXL->Compatible(XL,&flag); CHKERRQ(info);
1179:   if (flag == TAO_FALSE){
1180:     SETERRQ(1,"Dual bound vectors not Compatible");
1181:   }

1183:   if (tao->CopyDuals){
1184:     info = (*tao->CopyDuals)(tao,DXL,DXU,tao->data);CHKERRQ(info);
1185:   } else {
1186:     info=DXL->SetToZero();CHKERRQ(info);
1187:     info=DXU->SetToZero();CHKERRQ(info);
1188:   }

1190:   TaoFunctionReturn(0);
1191: }


1196: /* ---------------------------------------------------------- */
1197: /* @C
1198:    TaoSetInitialVector - Sets the initial vector used by the TAO
1199:    solver.  

1201:    Collective on TAO_SOLVER

1203:    Input Parameters:
1204: +  tao - the TAO solver
1205: -  xx0 - vector used for initial point (set xx0==TAO_NULL for default)

1207:    Notes:
1208:    By default the TAO solvers use an initial starting guess of zero.  
1209:    To provide an alternative initial guess, the user must call 
1210:    TaoSetInitialVector() before calling TaoSolve().

1212:    This vector will replace the variable vector set in the TaoCreate() routine.

1214:    The user is responsible for destroying this vector.

1216:    If this vector is TAO_NULL, TAO will use the set the previous variable 
1217:    vector to a default starting point.

1219:    Level: developer

1221: .seealso: TaoSolve(), TaoGetSolution()
1222: @ */
1223: int TaoSetInitialVector(TAO_SOLVER tao,TaoVec *xx0)
1224: {
1225:   int info;
1226:   TaoTruth flag;
1227:   TaoVec* X;

1229:   TaoFunctionBegin;
1230:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
1231:   if (xx0==TAO_NULL){
1232:     //    tao->userstart=TAO_FALSE;
1233:   } else {
1234:     info=TaoGetSolution(tao,&X);CHKERRQ(info);
1235:     info=X->Compatible(xx0,&flag);CHKERRQ(info);
1236:     if (flag == TAO_FALSE){
1237:       SETERRQ(1,"New TAO variable vector must have identical structure as the previous variable vector.");
1238:     }
1239:     tao->vec_sol=xx0;
1240:     /*    info=X->CopyFrom(xx0);CHKERRQ(info);   */
1241:     //    tao->userstart=TAO_TRUE;
1242:   }
1243:   TaoFunctionReturn(0);
1244: }


1249: /*@C
1250:    TaoGetVariableBounds - Sets the vector pointers to the vectors 
1251:    containing the upper and lower bounds on the variables.

1253:    Collective on TAO_SOLVER

1255:    Input Parameter:
1256: .  tao - the TAO_SOLVER solver context

1258:    Output Parameters:
1259: +  xxll - Pointer to lower bounds on all the variables
1260: -  xxuu - Pointer to upper bounds on all the variables

1262:    Level: advanced

1264: .keywords: bounds, View

1266: @*/
1267: int TaoGetVariableBounds(TAO_SOLVER tao,TaoVec **xxll,TaoVec **xxuu)
1268: {
1269:   TaoFunctionBegin;
1270:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
1271:   if (xxll){
1272:     *xxll=tao->XL;
1273:   }
1274:   if (xxuu){
1275:     *xxuu=tao->XU;
1276:   }
1277:   TaoFunctionReturn(0);
1278: }


1281: /* ---------------------------------------------------------- */
1284: /*@ 
1285:    TaoLMVMSetSize - Sets the number of previous points and gradients to
1286:    be used in calculating the step direction for the limited memory
1287:    variable metric methods.

1289:    Collective on TAO_SOLVER

1291:    Input Parameters:
1292: +  tao - the TAO_SOLVER context
1293: -  lm - the number of previous points and gradients to be used.

1295:    Output Parameter:

1297:    Options Database Keys: 
1298: .  -tao_lmvm_lm <lm>

1300:    Level: intermediate

1302: .keywords: method

1304: @*/
1305: int TaoLMVMSetSize(TAO_SOLVER tao,int lm)
1306: {
1307:   TaoFunctionBegin;
1308:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
1309:   if (lm < 1) SETERRQ(1,"Gradient History must be positive");
1310:   tao->lm=lm;

1312:   TaoFunctionReturn(0);
1313: }

1317: /*@C
1318:    TaoLMVMGetSize - Gets the number of previous points and gradients to
1319:    be used in calculating the step direction for the limited memory
1320:    variable metric methods.

1322:    Collective on TAO_SOLVER

1324:    Input Parameters:
1325: .  tao - the TAO_SOLVER context

1327:    Output Parameter:
1328: .  lm - the number of previous points and gradients to be used.

1330:    Level: intermediate

1332: @*/
1333: int TaoLMVMGetSize(TAO_SOLVER tao,int *lm)
1334: {
1335:   TaoFunctionBegin;
1336:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);
1337:   if (lm){
1338:     *lm=tao->lm;
1339:   }
1340:   TaoFunctionReturn(0);
1341: }


1344: /* ---------------------------------------------------------- */
1347: /*@C
1348:    TaoSetTerminationReason - Sets the termination reason

1350:    Collective on TAO_SOLVER

1352:    Input Parameters:
1353: +  tao - the TAO_SOLVER context
1354: -  reason - one of

1356: $    TAO_CONVERGED_ATOL (2),        (res <= atol)  
1357: $    TAO_CONVERGED_RTOL (3),        (res/res0 <= rtol) 
1358: $    TAO_CONVERGED_TRTOL (4),       (xdiff <= trtol) 
1359: $    TAO_CONVERGED_MINF (5),        (f <= fmin)
1360: $    TAO_CONVERGED_USER (6),        (user defined)

1362: $    TAO_DIVERGED_MAXITS (-2),      (its>maxits)
1363: $    TAO_DIVERGED_NAN (-4),         (Numerical problems)
1364: $    TAO_DIVERGED_MAXFCN (-5),      (nfunc > maxnfuncts)
1365: $    TAO_DIVERGED_LS_FAILURE (-6),  (line search failure)
1366: $    TAO_DIVERGED_TR_REDUCTION (-7),
1367: $    TAO_DIVERGED_USER (-8),        (user defined)

1369: $    TAO_CONTINUE_ITERATING  (0)

1371:    where
1372: +  res - residual of optimality conditions
1373: .  res0 - initial residual of optimality conditions
1374: .  xdiff - current trust region size
1375: .  f - function value
1376: .  atol - absolute tolerance
1377: .  rtol - relative tolerance
1378: .  its - current iterate number
1379: .  maxits - maximum number of iterates
1380: .  nfunc - number of function evaluations
1381: -  maxnfuncts - maximum number of function evaluations


1384:    Output Parameter:

1386:    Level: intermediate

1388: .seealso TaoGetTerminationReason(), TaoAppSetMonitor(), TaoSetMonitor()

1390: .keywords: convergence

1392: @*/
1393: int TaoSetTerminationReason(TAO_SOLVER tao,TaoTerminateReason reason)
1394: {
1395:   TaoFunctionBegin;
1396:   TaoValidHeaderSpecific(tao,TAO_COOKIE,1);

1398:   tao->reason=reason;

1400:   TaoFunctionReturn(0);
1401: }


1404: /* ------------ Routines to called when destroying this application ----------- */
1407: /*@C
1408:    TaoSetDestroyRoutine - Sets an ADDITIONAL function that will be called when
1409:    this object is destroyed.

1411:    Collective on TAO_SOLVER

1413:    Input Parameters:
1414: +  taoapp - the TAO_SOLVER solver context
1415: .  destroy - function pointer
1416: -  mctx - [optional] user-defined context for private data for the 
1417:           destroy routine (may be TAO_NULL)

1419:    Calling sequence of destroy:
1420: $     int mydestroy(void *mctx)

1422: .    mctx - [optional] destroy context


1425:    Level: intermediate

1427: .keywords: destroy

1429: .seealso: TaoSetMonitor(), TaoDestroy()
1430: @*/
1431: int TaoSetDestroyRoutine(TAO_SOLVER tao,int (*destroy)(void*),void *mctx)
1432: {
1433:   TaoFunctionBegin;
1434:   if (destroy){
1435:     if (tao->numberdestroyers >= MAX_TAO_DESTROY) {
1436:       SETERRQ(1,"TAO ERRROR: Too many TAO destroy routines set");
1437:     }
1438: 
1439:     tao->userdestroy[tao->numberdestroyers]           = destroy;
1440:     tao->userctxdestroy[tao->numberdestroyers++]      = mctx;
1441:   }
1442:   TaoFunctionReturn(0);
1443: }