LIS_INT lis_bicr_quad(LIS_SOLVER solver)
{
  LIS_MATRIX A,At;
  LIS_PRECON M;
  LIS_VECTOR b,x;
  LIS_VECTOR r,rtld, z,ztld,p, ptld, ap, map, az, aptld;
  LIS_QUAD_PTR alpha, beta, rho, rho_old, tmpdot1;
  LIS_REAL   bnrm2, nrm2, tol;
  LIS_INT iter,maxiter,n,output,conv;
  double times,ptimes;

  LIS_DEBUG_FUNC_IN;

  A       = solver->A;
  At      = solver->A;
  M       = solver->precon;
  b       = solver->b;
  x       = solver->x;
  n       = A->n;
  maxiter = solver->options[LIS_OPTIONS_MAXITER];
  output  = solver->options[LIS_OPTIONS_OUTPUT];
  conv    = solver->options[LIS_OPTIONS_CONV_COND];
  ptimes  = 0.0;

  r       = solver->work[0];
  rtld    = solver->work[1];
  z       = solver->work[2];
  ztld    = solver->work[3];
  p       = solver->work[4];
  ptld    = solver->work[5];
  ap      = solver->work[6];
  az      = solver->work[7];
  map     = solver->work[8];
  aptld   = solver->work[9];

  LIS_QUAD_SCALAR_MALLOC(alpha,0,1);
  LIS_QUAD_SCALAR_MALLOC(beta,1,1);
  LIS_QUAD_SCALAR_MALLOC(rho,2,1);
  LIS_QUAD_SCALAR_MALLOC(rho_old,3,1);
  LIS_QUAD_SCALAR_MALLOC(tmpdot1,4,1);

  /* Initial Residual */
  if( lis_solver_get_initial_residual(solver,NULL,NULL,r,&bnrm2) )
  {
    LIS_DEBUG_FUNC_OUT;
    return LIS_SUCCESS;
  }
  tol     = solver->tol;

  lis_solver_set_shadowresidual(solver,r,rtld);

  lis_psolve(solver, r, z);
  lis_psolvet(solver, rtld, ztld);
  lis_vector_copyex_mm(z,p);
  lis_vector_copyex_mm(ztld,ptld);
  LIS_MATVEC(A,z,ap);
  lis_vector_dotex_mmm(ap,ztld,&rho_old);

  for( iter=1; iter<=maxiter; iter++ )
  {
    /* aptld = A^T * ptld */
    /* map   = M^-1 * ap  */
    LIS_MATVECT(A,ptld,aptld);
    times = lis_wtime();
    lis_psolve(solver, ap, map);
    ptimes += lis_wtime()-times;

    /* tmpdot1 = <map,aptld> */
    lis_vector_dotex_mmm(map,aptld,&tmpdot1);
    /* test breakdown */
    if( tmpdot1.hi[0]==0.0 && tmpdot1.lo[0]==0.0 )
    {
      solver->retcode   = LIS_BREAKDOWN;
      solver->iter      = iter;
      solver->resid     = nrm2;
      LIS_DEBUG_FUNC_OUT;
      return LIS_BREAKDOWN;
    }

    /* alpha = rho_old / tmpdot1 */
    /* x     = x + alpha*p   */
    /* r     = r - alpha*ap  */
    lis_quad_div((LIS_QUAD *)alpha.hi,(LIS_QUAD *)rho_old.hi,(LIS_QUAD *)tmpdot1.hi);
    lis_vector_axpyex_mmm(alpha,p,x);
    lis_quad_minus((LIS_QUAD *)alpha.hi);
    lis_vector_axpyex_mmm(alpha,ap,r);
    /* convergence check */
    lis_solver_get_residual[conv](r,solver,&nrm2);

    if( output )
    {
      if( output & LIS_PRINT_MEM ) solver->residual[iter] = nrm2;
      if( output & LIS_PRINT_OUT && A->my_rank==0 ) lis_print_rhistory(iter,nrm2);
    }

    if( tol >= nrm2 )
    {
      solver->retcode    = LIS_SUCCESS;
      solver->iter       = iter;
      solver->resid      = nrm2;
      solver->ptimes     = ptimes;
      LIS_DEBUG_FUNC_OUT;
      return LIS_SUCCESS;
    }
    
    /* rtld = rtld - alpha*aptld */
    /* z    = z - alpha*map      */
    /* ztld = M^-T * rtld        */
    /* az   = A * z              */
    /* rho = <az,ztld>           */
    lis_vector_axpyex_mmm(alpha,aptld,rtld);
    lis_vector_axpyex_mmm(alpha,map,z);
    times = lis_wtime();
    lis_psolvet(solver, rtld, ztld);
    ptimes += lis_wtime()-times;
    LIS_MATVEC(A,z,az);
    lis_vector_dotex_mmm(az,ztld,&rho);

    /* test breakdown */
    if( rho.hi[0]==0.0 && rho.lo[0]==0.0 )
    {
      solver->retcode   = LIS_BREAKDOWN;
      solver->iter      = iter;
      solver->resid     = nrm2;
      LIS_DEBUG_FUNC_OUT;
      return LIS_BREAKDOWN;
    }

    /* beta = rho / rho_old    */
    /* p    = z    + beta*p    */
    /* ptld = ztld + beta*ptld */
    /* ap   = az   + beta*ap   */
    lis_quad_div((LIS_QUAD *)beta.hi,(LIS_QUAD *)rho.hi,(LIS_QUAD *)rho_old.hi);
    lis_vector_xpayex_mmm(z,beta,p);
    lis_vector_xpayex_mmm(ztld,beta,ptld);
    lis_vector_xpayex_mmm(az,beta,ap);

    rho_old.hi[0] = rho.hi[0];
    rho_old.lo[0] = rho.lo[0];
  }

  solver->retcode   = LIS_MAXITER;
  solver->iter      = iter;
  solver->resid     = nrm2;
  LIS_DEBUG_FUNC_OUT;
  return LIS_MAXITER;
}
LIS_INT lis_bicg_switch(LIS_SOLVER solver)
{
  LIS_MATRIX A,At;
  LIS_PRECON M;
  LIS_VECTOR b,x;
  LIS_VECTOR r,rtld, z,ztld,p, ptld, q, qtld;
  LIS_QUAD_PTR alpha, beta, rho, rho_old, tmpdot1;
  LIS_REAL   bnrm2, nrm2, tol, tol2;
  LIS_INT iter,maxiter,n,output,conv;
  LIS_INT iter2,maxiter2;
  double times,ptimes;

  LIS_DEBUG_FUNC_IN;


  A       = solver->A;
  At      = solver->A;
  M        = solver->precon;
  b        = solver->b;
  x        = solver->x;
  n        = A->n;
  maxiter  = solver->options[LIS_OPTIONS_MAXITER];
  maxiter2 = solver->options[LIS_OPTIONS_SWITCH_MAXITER];
  output   = solver->options[LIS_OPTIONS_OUTPUT];
  conv    = solver->options[LIS_OPTIONS_CONV_COND];
  tol      = solver->params[LIS_PARAMS_RESID-LIS_OPTIONS_LEN];
  tol2     = solver->params[LIS_PARAMS_SWITCH_RESID-LIS_OPTIONS_LEN];
  ptimes   = 0.0;

  r        = solver->work[0];
  rtld     = solver->work[1];
  z        = solver->work[2];
  ztld     = solver->work[3];
  p        = solver->work[4];
  ptld     = solver->work[5];
  q        = solver->work[2];
  qtld     = solver->work[3];

  LIS_QUAD_SCALAR_MALLOC(alpha,0,1);
  LIS_QUAD_SCALAR_MALLOC(beta,1,1);
  LIS_QUAD_SCALAR_MALLOC(rho,2,1);
  LIS_QUAD_SCALAR_MALLOC(rho_old,3,1);
  LIS_QUAD_SCALAR_MALLOC(tmpdot1,4,1);
  rho_old.hi[0] = 1.0;
  rho_old.lo[0] = 0.0;


  /* Initial Residual */
  if( lis_solver_get_initial_residual(solver,NULL,NULL,r,&bnrm2) )
  {
    LIS_DEBUG_FUNC_OUT;
    return LIS_SUCCESS;
  }
  tol2     = solver->tol_switch;

  lis_solver_set_shadowresidual(solver,r,rtld);

  lis_vector_set_allex_nm(0.0, p);
  lis_vector_set_allex_nm(0.0, ptld);

  r->precision = LIS_PRECISION_DEFAULT;
  rtld->precision = LIS_PRECISION_DEFAULT;
  p->precision = LIS_PRECISION_DEFAULT;
  ptld->precision = LIS_PRECISION_DEFAULT;

  for( iter=1; iter<=maxiter2; iter++ )
  {
    /* z    = M^-1 * r */
    /* ztld = M^-T * rtld */
    times = lis_wtime();
    lis_psolve(solver, r, z);
    lis_psolvet(solver, rtld, ztld);
    ptimes += lis_wtime()-times;

    /* rho = <z,rtld> */
    lis_vector_dot(z,rtld,&rho.hi[0]);

    /* test breakdown */
    if( rho.hi[0]==0.0 )
    {
      solver->retcode   = LIS_BREAKDOWN;
      solver->iter      = iter;
      solver->iter2     = iter;
      solver->resid     = nrm2;
      LIS_DEBUG_FUNC_OUT;
      return LIS_BREAKDOWN;
    }

    /* beta = (rho / rho_old) */
    beta.hi[0] = rho.hi[0] / rho_old.hi[0];

    /* p    = z    + beta*p    */
    /* ptld = ztld + beta*ptld */
    
    /* q    = A   * p    */
    /* qtld = A^T * ptld */
    lis_vector_xpay(z,beta.hi[0],p);
    LIS_MATVEC(A,p,q);

    lis_vector_xpay(ztld,beta.hi[0],ptld);
    LIS_MATVECT(At,ptld,qtld);

    
    /* tmpdot1 = <ptld,q> */
    lis_vector_dot(ptld,q,&tmpdot1.hi[0]);

    /* test breakdown */
    if( tmpdot1.hi[0]==0.0 )
    {
      solver->retcode   = LIS_BREAKDOWN;
      solver->iter      = iter;
      solver->iter2     = iter;
      solver->resid     = nrm2;
      LIS_DEBUG_FUNC_OUT;
      return LIS_BREAKDOWN;
    }
    
    /* alpha = rho / tmpdot1 */
    alpha.hi[0] = rho.hi[0] / tmpdot1.hi[0];
    
    /* x = x + alpha*p */
    lis_vector_axpy(alpha.hi[0],p,x);
    
    /* r    = r    - alpha*q    */
    lis_vector_axpy(-alpha.hi[0],q,r);
    
    /* convergence check */
    lis_solver_get_residual[conv](r,solver,&nrm2);

    if( output )
    {
      if( output & LIS_PRINT_MEM ) solver->residual[iter] = nrm2;
      if( output & LIS_PRINT_OUT && A->my_rank==0 ) lis_print_rhistory(iter,nrm2);
    }

    if( nrm2 <= tol2 )
    {
      solver->iter       = iter;
      solver->iter2     = iter;
      solver->ptimes     = ptimes;
      break;
    }
    
    /* rtld = rtld - alpha*qtld */
    lis_vector_axpy(-alpha.hi[0],qtld,rtld);

    rho_old.hi[0] = rho.hi[0];
  }

  r->precision = LIS_PRECISION_QUAD;
  rtld->precision = LIS_PRECISION_QUAD;
  p->precision = LIS_PRECISION_QUAD;
  ptld->precision = LIS_PRECISION_QUAD;

/*  solver->precon->precon_type = 0;*/
  solver->options[LIS_OPTIONS_INITGUESS_ZEROS] = LIS_FALSE;
  lis_vector_copyex_mn(x,solver->xx);
  rho_old.hi[0] = 1.0;
  lis_solver_get_initial_residual(solver,NULL,NULL,r,&bnrm2);
  tol     = solver->tol;

  lis_solver_set_shadowresidual(solver,r,rtld);

  lis_vector_set_allex_nm(0.0, p);
  lis_vector_set_allex_nm(0.0, ptld);

  for( iter2=iter+1; iter2<=maxiter; iter2++ )
  {
    /* z    = M^-1 * r */
    /* ztld = M^-T * rtld */
    times = lis_wtime();
    lis_psolve(solver, r, z);
    lis_psolvet(solver, rtld, ztld);
/*    memset(z->value_lo,0,n*sizeof(LIS_SCALAR));
    memset(ztld->value_lo,0,n*sizeof(LIS_SCALAR));*/
    ptimes += lis_wtime()-times;

    /* rho = <z,rtld> */
    lis_vector_dotex_mmm(z,rtld,&rho);
/*    printf("rho = %e %e\n",rho.hi[0],rho.lo[0]);*/

    /* test breakdown */
    if( rho.hi[0]==0.0 && rho.lo[0]==0.0 )
    {
      solver->retcode   = LIS_BREAKDOWN;
      solver->iter      = iter2;
      solver->resid     = nrm2;
      LIS_DEBUG_FUNC_OUT;
      return LIS_BREAKDOWN;
    }

    /* beta = (rho / rho_old) */
    lis_quad_div((LIS_QUAD *)beta.hi,(LIS_QUAD *)rho.hi,(LIS_QUAD *)rho_old.hi);

    /* p    = z    + beta*p    */
    /* ptld = ztld + beta*ptld */
    
    /* q    = A   * p    */
    /* qtld = A^T * ptld */
    lis_vector_xpayex_mmm(z,beta,p);
    LIS_MATVEC(A,p,q);

    lis_vector_xpayex_mmm(ztld,beta,ptld);
    LIS_MATVECT(At,ptld,qtld);

    
    /* tmpdot1 = <ptld,q> */
    lis_vector_dotex_mmm(ptld,q,&tmpdot1);

    /* test breakdown */
    if( tmpdot1.hi[0]==0.0 && tmpdot1.lo[0]==0.0 )
    {
      solver->retcode   = LIS_BREAKDOWN;
      solver->iter      = iter2;
      solver->resid     = nrm2;
      LIS_DEBUG_FUNC_OUT;
      return LIS_BREAKDOWN;
    }
    
    /* alpha = rho / tmpdot1 */
    lis_quad_div((LIS_QUAD *)alpha.hi,(LIS_QUAD *)rho.hi,(LIS_QUAD *)tmpdot1.hi);
    
    /* x = x + alpha*p */
    lis_vector_axpyex_mmm(alpha,p,x);
    
    /* r    = r    - alpha*q    */
    lis_quad_minus((LIS_QUAD *)alpha.hi);
    lis_vector_axpyex_mmm(alpha,q,r);
    
    /* convergence check */
    lis_solver_get_residual[conv](r,solver,&nrm2);
    if( output )
    {
      if( output & LIS_PRINT_MEM ) solver->residual[iter2] = nrm2;
      if( output & LIS_PRINT_OUT && A->my_rank==0 ) lis_print_rhistory(iter,nrm2);
    }

    if( tol > nrm2 )
    {
      solver->retcode    = LIS_SUCCESS;
      solver->iter       = iter2;
      solver->iter2      = iter;
      solver->resid      = nrm2;
      solver->ptimes     = ptimes;
      LIS_DEBUG_FUNC_OUT;
      return LIS_SUCCESS;
    }
    
    /* rtld = rtld - alpha*qtld */
    lis_vector_axpyex_mmm(alpha,qtld,rtld);

    rho_old.hi[0] = rho.hi[0];
    rho_old.lo[0] = rho.lo[0];
  }

  solver->retcode   = LIS_MAXITER;
  solver->iter      = iter2;
  solver->iter2     = iter;
  solver->resid     = nrm2;
  LIS_DEBUG_FUNC_OUT;
  return LIS_MAXITER;
}
示例#3
0
LIS_INT lis_bicr(LIS_SOLVER solver)
{
	LIS_MATRIX A;
	LIS_VECTOR x;
	LIS_VECTOR r,rtld, z,ztld,p, ptld, ap, map, az, aptld;
	LIS_SCALAR alpha, beta, rho, rho_old, tmpdot1;
	LIS_REAL bnrm2, nrm2, tol;
	LIS_INT iter,maxiter,output,conv;
	double time,ptime;

	LIS_DEBUG_FUNC_IN;

	A       = solver->A;
	x       = solver->x;
	maxiter = solver->options[LIS_OPTIONS_MAXITER];
	output  = solver->options[LIS_OPTIONS_OUTPUT];
	conv    = solver->options[LIS_OPTIONS_CONV_COND];
	ptime   = 0.0;

	r       = solver->work[0];
	rtld    = solver->work[1];
	z       = solver->work[2];
	ztld    = solver->work[3];
	p       = solver->work[4];
	ptld    = solver->work[5];
	ap      = solver->work[6];
	az      = solver->work[7];
	map     = solver->work[8];
	aptld   = solver->work[9];



	/* Initial Residual */
	if( lis_solver_get_initial_residual(solver,NULL,NULL,r,&bnrm2) )
	{
		LIS_DEBUG_FUNC_OUT;
		return LIS_SUCCESS;
	}
	tol     = solver->tol;

	lis_solver_set_shadowresidual(solver,r,rtld);

	lis_psolve(solver, r, z);
	lis_psolvet(solver, rtld, ztld);
	lis_vector_copy(z,p);
	lis_vector_copy(ztld,ptld);
	lis_matvec(A,z,ap);
	lis_vector_dot(ap,ztld,&rho_old);

	for( iter=1; iter<=maxiter; iter++ )
	{
		/* aptld = A^T * ptld */
		/* map   = M^-1 * ap  */
		lis_matvect(A,ptld,aptld);
		time = lis_wtime();
		lis_psolve(solver, ap, map);
		ptime += lis_wtime()-time;

		/* tmpdot1 = <map,aptld> */
		lis_vector_dot(map,aptld,&tmpdot1);
		/* test breakdown */
		if( tmpdot1==0.0 )
		{
			solver->retcode   = LIS_BREAKDOWN;
			solver->iter      = iter;
			solver->resid     = nrm2;
			LIS_DEBUG_FUNC_OUT;
			return LIS_BREAKDOWN;
		}

		/* alpha = rho_old / tmpdot1 */
		/* x     = x + alpha*p   */
		/* r     = r - alpha*ap  */
		alpha = rho_old / tmpdot1;
		lis_vector_axpy(alpha,p,x);
		lis_vector_axpy(-alpha,ap,r);
		/* convergence check */
		lis_solver_get_residual[conv](r,solver,&nrm2);

		if( output )
		{
			if( output & LIS_PRINT_MEM ) solver->rhistory[iter] = nrm2;
			if( output & LIS_PRINT_OUT && A->my_rank==0 ) lis_print_rhistory(iter,nrm2);
		}

		if( tol >= nrm2 )
		{
			solver->retcode    = LIS_SUCCESS;
			solver->iter       = iter;
			solver->resid      = nrm2;
			solver->ptime      = ptime;
			LIS_DEBUG_FUNC_OUT;
			return LIS_SUCCESS;
		}
		
		/* rtld = rtld - alpha*aptld */
		/* z    = z - alpha*map      */
		/* ztld = M^-T * rtld        */
		/* az   = A * z              */
		/* rho = <az,ztld>           */
		lis_vector_axpy(-alpha,aptld,rtld);
		lis_vector_axpy(-alpha,map,z);
		time = lis_wtime();
		lis_psolvet(solver, rtld, ztld);
		ptime += lis_wtime()-time;
		lis_matvec(A,z,az);
		lis_vector_dot(az,ztld,&rho);

		/* test breakdown */
		if( rho==0.0 )
		{
			solver->retcode   = LIS_BREAKDOWN;
			solver->iter      = iter;
			solver->resid     = nrm2;
			LIS_DEBUG_FUNC_OUT;
			return LIS_BREAKDOWN;
		}

		/* beta = rho / rho_old    */
		/* p    = z    + beta*p    */
		/* ptld = ztld + beta*ptld */
		/* ap   = az   + beta*ap   */
		beta = rho / rho_old;
		lis_vector_xpay(z,beta,p);
		lis_vector_xpay(ztld,beta,ptld);
		lis_vector_xpay(az,beta,ap);

		rho_old = rho;
	}

	solver->retcode   = LIS_MAXITER;
	solver->iter      = iter;
	solver->resid     = nrm2;
	LIS_DEBUG_FUNC_OUT;
	return LIS_MAXITER;
}
LIS_INT lis_bicg(LIS_SOLVER solver)
{
  LIS_MATRIX A,At;
  LIS_PRECON M;
  LIS_VECTOR b,x;
  LIS_VECTOR r,rtld, z,ztld,p, ptld, q, qtld;
  LIS_SCALAR alpha, beta, rho, rho_old, tmpdot1;
  LIS_REAL   bnrm2, nrm2, tol;
  LIS_INT iter,maxiter,n,output,conv;
  double times,ptimes;

  LIS_DEBUG_FUNC_IN;

  A       = solver->A;
  At      = solver->A;
  M       = solver->precon;
  b       = solver->b;
  x       = solver->x;
  n       = A->n;
  maxiter = solver->options[LIS_OPTIONS_MAXITER];
  output  = solver->options[LIS_OPTIONS_OUTPUT];
  conv    = solver->options[LIS_OPTIONS_CONV_COND];
  ptimes  = 0.0;

  r       = solver->work[0];
  rtld    = solver->work[1];
  z       = solver->work[2];
  ztld    = solver->work[3];
  p       = solver->work[4];
  ptld    = solver->work[5];
  q       = solver->work[2];
  qtld    = solver->work[3];
  rho_old = (LIS_SCALAR)1.0;



  /* Initial Residual */
  if( lis_solver_get_initial_residual(solver,NULL,NULL,r,&bnrm2) )
  {
    LIS_DEBUG_FUNC_OUT;
    return LIS_SUCCESS;
  }
  tol     = solver->tol;

  lis_solver_set_shadowresidual(solver,r,rtld);

  lis_vector_set_all(0, p);
  lis_vector_set_all(0, ptld);

  for( iter=1; iter<=maxiter; iter++ )
  {
    /* z    = M^-1 * r */
    /* ztld = M^-T * rtld */
    times = lis_wtime();
    lis_psolve(solver, r, z);
    lis_psolvet(solver, rtld, ztld);
    ptimes += lis_wtime()-times;

    /* rho = <z,rtld> */
    lis_vector_dot(z,rtld,&rho);
/*    printf("rho = %e\n",rho);*/

    /* test breakdown */
    if( rho==0.0 )
    {
      solver->retcode   = LIS_BREAKDOWN;
      solver->iter      = iter;
      solver->resid     = nrm2;
      LIS_DEBUG_FUNC_OUT;
      return LIS_BREAKDOWN;
    }

    /* beta = (rho / rho_old) */
    beta = rho / rho_old;

    /* p    = z    + beta*p    */
    /* ptld = ztld + beta*ptld */
    
    /* q    = A   * p    */
    /* qtld = A^T * ptld */
    lis_vector_xpay(z,beta,p);
    LIS_MATVEC(A,p,q);

    lis_vector_xpay(ztld,beta,ptld);
    LIS_MATVECT(At,ptld,qtld);

    
    /* tmpdot1 = <ptld,q> */
    lis_vector_dot(ptld,q,&tmpdot1);
/*    printf("tmpdot1 = %e\n",tmpdot1);*/

    /* test breakdown */
    if( tmpdot1==0.0 )
    {
      solver->retcode   = LIS_BREAKDOWN;
      solver->iter      = iter;
      solver->resid     = nrm2;
      LIS_DEBUG_FUNC_OUT;
      return LIS_BREAKDOWN;
    }
    
    /* alpha = rho / tmpdot1 */
    alpha = rho / tmpdot1;
    
    /* x = x + alpha*p */
    lis_vector_axpy(alpha,p,x);
    
    /* r    = r    - alpha*q    */
    lis_vector_axpy(-alpha,q,r);
    
    /* convergence check */
    lis_solver_get_residual[conv](r,solver,&nrm2);

    if( output )
    {
      if( output & LIS_PRINT_MEM ) solver->residual[iter] = nrm2;
      if( output & LIS_PRINT_OUT && A->my_rank==0 ) lis_print_rhistory(iter,nrm2);
    }

    if( tol >= nrm2 )
    {
      solver->retcode    = LIS_SUCCESS;
      solver->iter       = iter;
      solver->resid      = nrm2;
      solver->ptimes     = ptimes;
      LIS_DEBUG_FUNC_OUT;
      return LIS_SUCCESS;
    }
    
    /* rtld = rtld - alpha*qtld */
    lis_vector_axpy(-alpha,qtld,rtld);

    rho_old = rho;
  }

  solver->retcode   = LIS_MAXITER;
  solver->iter      = iter;
  solver->resid     = nrm2;
  LIS_DEBUG_FUNC_OUT;
  return LIS_MAXITER;
}
示例#5
0
LIS_INT lis_bicg_quad(LIS_SOLVER solver)
{
	LIS_MATRIX A,At;
	LIS_VECTOR x;
	LIS_VECTOR r,rtld, z,ztld,p, ptld, q, qtld;
	LIS_QUAD_PTR alpha, beta, rho, rho_old, tmpdot1;
	LIS_REAL bnrm2, nrm2, tol;
	LIS_INT iter,maxiter,output,conv;
	double time,ptime;

	LIS_DEBUG_FUNC_IN;

	A       = solver->A;
	At      = solver->A;
	x       = solver->x;
	maxiter = solver->options[LIS_OPTIONS_MAXITER];
	output  = solver->options[LIS_OPTIONS_OUTPUT];
	conv    = solver->options[LIS_OPTIONS_CONV_COND];
	ptime   = 0.0;

	r       = solver->work[0];
	rtld    = solver->work[1];
	z       = solver->work[2];
	ztld    = solver->work[3];
	p       = solver->work[4];
	ptld    = solver->work[5];
	q       = solver->work[2];
	qtld    = solver->work[3];

	LIS_QUAD_SCALAR_MALLOC(alpha,0,1);
	LIS_QUAD_SCALAR_MALLOC(beta,1,1);
	LIS_QUAD_SCALAR_MALLOC(rho,2,1);
	LIS_QUAD_SCALAR_MALLOC(rho_old,3,1);
	LIS_QUAD_SCALAR_MALLOC(tmpdot1,4,1);
	rho_old.hi[0] = 1.0;
	rho_old.lo[0] = 0.0;

	/* Initial Residual */
	if( lis_solver_get_initial_residual(solver,NULL,NULL,r,&bnrm2) )
	{
		LIS_DEBUG_FUNC_OUT;
		return LIS_SUCCESS;
	}
	tol     = solver->tol;

	lis_solver_set_shadowresidual(solver,r,rtld);

	lis_vector_set_allex_nm(0.0, p);
	lis_vector_set_allex_nm(0.0, ptld);

	for( iter=1; iter<=maxiter; iter++ )
	{
		/* z    = M^-1 * r */
		/* ztld = M^-T * rtld */
		time = lis_wtime();
		lis_psolve(solver, r, z);
		lis_psolvet(solver, rtld, ztld);
		ptime += lis_wtime()-time;

		/* rho = <z,rtld> */
		lis_vector_dotex_mmm(z,rtld,&rho);
/*		printf("rho = %e %e\n",rho.hi[0],rho.lo[0]);*/

		/* test breakdown */
		if( rho.hi[0]==0.0 && rho.lo[0]==0.0 )
		{
			solver->retcode   = LIS_BREAKDOWN;
			solver->iter      = iter;
			solver->resid     = nrm2;
			LIS_DEBUG_FUNC_OUT;
			return LIS_BREAKDOWN;
		}

		/* beta = (rho / rho_old) */
		lis_quad_div((LIS_QUAD *)beta.hi,(LIS_QUAD *)rho.hi,(LIS_QUAD *)rho_old.hi);
/*		printf("beta = %e %e\n",beta.hi[0],beta.lo[0]);*/

		/* p    = z    + beta*p    */
		/* ptld = ztld + beta*ptld */
		
		/* q    = A   * p    */
		/* qtld = A^T * ptld */
		lis_vector_xpayex_mmm(z,beta,p);
		lis_matvec(A,p,q);

		lis_vector_xpayex_mmm(ztld,beta,ptld);
		lis_matvect(At,ptld,qtld);

		
		/* tmpdot1 = <ptld,q> */
		lis_vector_dotex_mmm(ptld,q,&tmpdot1);
/*		printf("tmpdot1 = %e %e\n",tmpdot1.hi[0],tmpdot1.lo[0]);*/

		/* test breakdown */
		if( tmpdot1.hi[0]==0.0 && tmpdot1.lo[0]==0.0 )
		{
			solver->retcode   = LIS_BREAKDOWN;
			solver->iter      = iter;
			solver->resid     = nrm2;
			LIS_DEBUG_FUNC_OUT;
			return LIS_BREAKDOWN;
		}
		
		/* alpha = rho / tmpdot1 */
		lis_quad_div((LIS_QUAD *)alpha.hi,(LIS_QUAD *)rho.hi,(LIS_QUAD *)tmpdot1.hi);
/*		printf("alpha = %e %e\n",alpha.hi[0],alpha.lo[0]);*/
		
		/* x = x + alpha*p */
		lis_vector_axpyex_mmm(alpha,p,x);
		
		/* r    = r    - alpha*q    */
		lis_quad_minus((LIS_QUAD *)alpha.hi);
		lis_vector_axpyex_mmm(alpha,q,r);

		/* convergence check */
		lis_solver_get_residual[conv](r,solver,&nrm2);
		if( output )
		{
			if( output & LIS_PRINT_MEM ) solver->rhistory[iter] = nrm2;
			if( output & LIS_PRINT_OUT && A->my_rank==0 ) lis_print_rhistory(iter,nrm2);
		}

		if( tol > nrm2 )
		{
			solver->retcode    = LIS_SUCCESS;
			solver->iter       = iter;
			solver->resid      = nrm2;
			solver->ptime      = ptime;
			LIS_DEBUG_FUNC_OUT;
			return LIS_SUCCESS;
		}
		
		/* rtld = rtld - alpha*qtld */
		lis_vector_axpyex_mmm(alpha,qtld,rtld);

		rho_old.hi[0] = rho.hi[0];
		rho_old.lo[0] = rho.lo[0];
	}

	solver->retcode   = LIS_MAXITER;
	solver->iter      = iter;
	solver->resid     = nrm2;
	LIS_DEBUG_FUNC_OUT;
	return LIS_MAXITER;
}