/*$Id: cg.c 1.94 05/02/11 14:10:19-06:00 benson@rockies.mcs.anl.gov $*/

#include "cg.h"                           /*I "tao_solver.h" I*/

/* ---------------------------------------------------------- */
#undef __FUNCT__  
#define __FUNCT__ "TaoSetUp_CG"
int TaoSetUp_CG(TAO_SOLVER tao,void *solver){

  TAO_CG *cg = (TAO_CG *) solver;
  TaoVec *xx;
  int    info;

  TaoFunctionBegin;
  
  info = TaoGetSolution(tao,&xx);CHKERRQ(info);
    
  info = xx->Clone(&cg->G); CHKERRQ(info);
  info = xx->Clone(&cg->Work); CHKERRQ(info);
  info = xx->Clone(&cg->DX); CHKERRQ(info);
  info = xx->Clone(&cg->Gprev); CHKERRQ(info);

  info = TaoSetLagrangianGradientVector(tao,cg->G);CHKERRQ(info);
  info = TaoSetStepDirectionVector(tao,cg->DX);CHKERRQ(info);

  TaoFunctionReturn(0);
}

/* ---------------------------------------------------------- */
#undef __FUNCT__  
#define __FUNCT__ "TaoDestroy_CG"
int TaoDestroy_CG(TAO_SOLVER tao, void *solver)
{
  TAO_CG *cg = (TAO_CG *) solver;
  int    info;

  TaoFunctionBegin;

  info = TaoVecDestroy(cg->Work);CHKERRQ(info);
  info = TaoVecDestroy(cg->DX);CHKERRQ(info);
  info = TaoVecDestroy(cg->Gprev);CHKERRQ(info);
  info = TaoVecDestroy(cg->G);CHKERRQ(info);

  info = TaoSetLagrangianGradientVector(tao,0);CHKERRQ(info);
  info = TaoSetStepDirectionVector(tao,0);CHKERRQ(info);

  TaoFunctionReturn(0);
}


/*------------------------------------------------------------*/
#undef __FUNCT__  
#define __FUNCT__ "TaoSetOptions_CG"
int TaoSetOptions_CG(TAO_SOLVER tao, void*solver)
{
  TAO_CG *cg = (TAO_CG *)solver;
  double   dtmp;
  int      info;
  TaoTruth flg;

  TaoFunctionBegin;

  info = TaoOptionsHead("Nonlinear Conjugate Gradient method for unconstrained optimization");CHKERRQ(info);

  info = TaoOptionDouble("-tao_cg_restart","Restart method based on orthogonality of successive gradients","TaoCGSetRestartTol",cg->eta,&dtmp, &flg);CHKERRQ(info);
  if (flg){
    info =TaoCGSetRestartTol(tao,dtmp);
  }

  info = TaoLineSearchSetFromOptions(tao);CHKERRQ(info);
  info = TaoOptionsTail();CHKERRQ(info);

  TaoFunctionReturn(0);
}


/*------------------------------------------------------------*/
#undef __FUNCT__  
#define __FUNCT__ "TaoView_CG"
int TaoView_CG(TAO_SOLVER tao,void* solver)
{
  TAO_CG   *cg = (TAO_CG *)solver;
  int      info;

  TaoFunctionBegin;

  info = TaoPrintInt(tao,"  cg restarts=%d,",cg->restarts);CHKERRQ(info);
  info = TaoPrintDouble(tao,"   tao_cg_restart=%g\n",cg->eta);CHKERRQ(info);
  info = TaoLineSearchView(tao);CHKERRQ(info);

  TaoFunctionReturn(0);
}


/* ---------------------------------------------------------- */
#undef __FUNCT__  
#define __FUNCT__ "TaoCGSetRestartTol"
/*@C
   TaoCGSetRestartTol - Set the nonlinear conjugate gradient restart
   tolerance.  The algorithm restarts when the gradient at the current 
   point, g(x^k), and the gradient of the previous point, g^{k-1}, 
   satisfy the following inequality: 
   | g(x^k)^T g(x^{k-1}) | / g(x^k)^T g(x^k) > eta.

   Collective on TAO_SOLVER

   Input Parameters:
+  tao - the TAO_SOLVER context
-  eta - the number of previous points and gradients to be used.

   Output Parameter:

   Level: intermediate

   Options Database Keys: 
.  -tao_cg_restart <eta> - sets the restart tolerance

@*/
int TaoCGSetRestartTol(TAO_SOLVER tao,double eta)
{
  TAO_CG *cg;
  int info;

  TaoFunctionBegin;
  info = TaoGetSolverContext(tao,"tao_cg_fr",(void**)&cg); CHKERRQ(info);
  if (!cg){
    info = TaoGetSolverContext(tao,"tao_cg_pr",(void**)&cg); CHKERRQ(info);
  }
  if (!cg){
    info = TaoGetSolverContext(tao,"tao_cg_prp",(void**)&cg); CHKERRQ(info);
  }
  if (cg){
    cg->eta=TaoMax(eta,0.0);
  }
  TaoFunctionReturn(0);
}
