void MatrixSymDiagStd::V_InvMtV(
  DVectorSlice* vs_lhs, BLAS_Cpp::Transp trans_rhs1
  , const SpVectorSlice& sv_rhs2) const
{
  const DVectorSlice diag = this->diag();
  size_type n = diag.size();

  // y = inv(op(A)) * x
  //
  // A is symmetric and diagonal A = diag(diag) so:
  //
  // y(j) = x(j) / diag(j), for j = 1...n
  //
  // x is sparse so take account of this.
  
  DenseLinAlgPack::Vp_MtV_assert_sizes( vs_lhs->size()
    , n, n, trans_rhs1, sv_rhs2.size() );

  for(   SpVectorSlice::const_iterator x_itr = sv_rhs2.begin()
     ; x_itr != sv_rhs2.end()
     ; ++x_itr )
  {
    (*vs_lhs)(x_itr->indice() + sv_rhs2.offset())
      = x_itr->value() / diag(x_itr->indice() + sv_rhs2.offset());
      // Note: The indice x(i) invocations are ranged check
      // if this is compiled into the code.
  }
}
bool DenseLinAlgPack::assert_print_nan_inf( const DVectorSlice& v
  , const std::string & name, bool throw_excpt, std::ostream* out )
{

  bool has_nan_or_inf = false;
  bool printed_header = false;

  for( DVectorSlice::const_iterator v_itr = v.begin(); v_itr != v.end(); ++v_itr ) {
    if( RTOp_is_nan_inf(*v_itr) ) {
      if(out) {
        if(!printed_header) {
          *out
            << "The vector \"" << name
            << "\" has the following NaN or Inf entries\n";
          printed_header = true;
        }
        *out
          << name << "(" << v_itr - v.begin() + 1 << ") = "
          << *v_itr << std::endl;
      }
      has_nan_or_inf = true;
    }
  }
  if( has_nan_or_inf && throw_excpt ) {
    if(out)
      out->flush();
    std::ostringstream omsg;
    omsg
      << "assert_print_nan_inf(...) : Error, the vector named "
      << name << " has at least one element which is NaN or Inf";
    throw NaNInfException( omsg.str() );
  }

  return !has_nan_or_inf;
}
bool DenseLinAlgPack::comp_less(const DVectorSlice& vs, value_type alpha)
{
  DVectorSlice::const_iterator vs_itr = vs.begin();
  const value_type denom = my_max( ::fabs(alpha), 1.0 );
  for(; vs_itr != vs.end(); ++vs_itr)
    if( *vs_itr > alpha ) return false;
  return true;
}
void DenseLinAlgPack::syr(value_type alpha, const DVectorSlice& vs_rhs, DMatrixSliceSym* sym_lhs)
{
  assert_gms_square(sym_lhs->gms());
  MtV_assert_sizes( sym_lhs->gms().rows(), sym_lhs->gms().cols()
    , BLAS_Cpp::no_trans, vs_rhs.dim() );
  BLAS_Cpp::syr( sym_lhs->uplo(), vs_rhs.dim(), alpha, vs_rhs.raw_ptr()
    , vs_rhs.stride(), sym_lhs->gms().col_ptr(1), sym_lhs->gms().max_rows() );
}
bool DenseLinAlgPack::comp(const DVectorSlice& vs1, const DVectorSlice& vs2) {
  DVectorSlice::const_iterator
    vs1_itr = vs1.begin(),
    vs2_itr = vs2.begin();
  for(; vs1_itr != vs1.end() && vs2_itr != vs2.end(); ++vs1_itr, ++vs2_itr)
    if( !_comp(*vs1_itr,*vs2_itr) ) return false;
  return true;
}
void DenseLinAlgPack::Vp_StMtV(DVectorSlice* vs_lhs, value_type alpha, const DMatrixSlice& gms_rhs1
  , BLAS_Cpp::Transp trans_rhs1, const DVectorSlice& vs_rhs2, value_type beta)
{
  Vp_MtV_assert_sizes(vs_lhs->dim(), gms_rhs1.rows()	, gms_rhs1.cols(), trans_rhs1
    , vs_rhs2.dim());
  BLAS_Cpp::gemv(trans_rhs1,gms_rhs1.rows(),gms_rhs1.cols(),alpha,gms_rhs1.col_ptr(1)
    ,gms_rhs1.max_rows(), vs_rhs2.raw_ptr(),vs_rhs2.stride(),beta,vs_lhs->raw_ptr()
    ,vs_lhs->stride());
}
void MatrixSymDiagStd::Vp_StMtV(
  DVectorSlice* vs_lhs, value_type alpha, BLAS_Cpp::Transp trans_rhs1
  , const DVectorSlice& vs_rhs2, value_type beta) const
{
  const DVectorSlice diag = this->diag();
  size_type n = diag.size();

  //
  // y = b*y + a * op(A) * x
  //
  DenseLinAlgPack::Vp_MtV_assert_sizes(
    vs_lhs->size(), n, n, trans_rhs1, vs_rhs2.size() );
  //
  // A is symmetric and diagonal A = diag(diag) so:
  //
  // y(j) += a * diag(j) * x(j), for j = 1...n
  //
  if( vs_rhs2.stride() == 1 && vs_lhs->stride() == 1 ) {
    // Optimized implementation
    const value_type
      *d_itr      = diag.raw_ptr(),
      *x_itr      = vs_rhs2.raw_ptr();
    value_type
      *y_itr      = vs_lhs->raw_ptr(),
      *y_end      = y_itr + vs_lhs->size();

    if( beta == 0.0 ) {
      while( y_itr != y_end )
        *y_itr++ = alpha * (*d_itr++) * (*x_itr++);
    }
    else if( beta == 1.0 ) {
      while( y_itr != y_end )
        *y_itr++ += alpha * (*d_itr++) * (*x_itr++);
    }
    else {
      for( ; y_itr != y_end; ++y_itr )
        *y_itr = beta * (*y_itr) + alpha * (*d_itr++) * (*x_itr++);
    }
  }
  else {
    // Generic implementation
    DVectorSlice::const_iterator
      d_itr = diag.begin(),
      x_itr = vs_rhs2.begin();
    DVectorSlice::iterator
      y_itr = vs_lhs->begin(),
      y_end = vs_lhs->end();
    for( ; y_itr != y_end; ++y_itr, ++d_itr, ++x_itr ) {
#ifdef LINALGPACK_CHECK_RANGE
      TEST_FOR_EXCEPT( !(  d_itr < diag.end()  ) );
      TEST_FOR_EXCEPT( !(  x_itr < vs_rhs2.end()  ) );
      TEST_FOR_EXCEPT( !(  y_itr < vs_lhs->end()  ) );
#endif
      *y_itr = beta * (*y_itr) + alpha * (*d_itr) * (*x_itr);
    }
  }
}
void DenseLinAlgPack::Vp_StMtV(DVectorSlice* vs_lhs, value_type alpha, const DMatrixSliceSym& sym_rhs1
  , BLAS_Cpp::Transp trans_rhs1, const DVectorSlice& vs_rhs2, value_type beta)
{
  assert_gms_square(sym_rhs1.gms());
  Vp_MtV_assert_sizes(vs_lhs->dim(), sym_rhs1.gms().rows(), sym_rhs1.gms().cols(), trans_rhs1
    , vs_rhs2.dim());
  BLAS_Cpp::symv(sym_rhs1.uplo(),sym_rhs1.gms().rows(),alpha,sym_rhs1.gms().col_ptr(1)
    ,sym_rhs1.gms().max_rows(),vs_rhs2.raw_ptr(),vs_rhs2.stride(),beta
    ,vs_lhs->raw_ptr(),vs_lhs->stride());
}
void MatrixSymPosDefLBFGS::Vp_DtV( DVectorSlice* y, const DVectorSlice& x ) const
{
  DenseLinAlgPack::Vp_MtV_assert_sizes(
    y->dim(), m_bar_, m_bar_, BLAS_Cpp::no_trans, x.dim() );

  DVectorSlice::const_iterator
    d_itr	= STY_.diag(0).begin(),
    x_itr	= x.begin();
  DVectorSlice::iterator
    y_itr	= y->begin();

  while( y_itr != y->end() )
    *y_itr++ += (*d_itr++) * (*x_itr++);		
}
void AbstractLinAlgPack::add_elements( SpVector* sv_lhs, value_type alpha, const DVectorSlice& vs_rhs
                   , size_type offset, bool add_zeros )
{
  typedef SpVector::element_type ele_t;
  const bool assume_sorted = !sv_lhs->nz() || ( sv_lhs->nz() && sv_lhs->is_sorted() );
  DVectorSlice::const_iterator
    itr = vs_rhs.begin();
  if(add_zeros) {
    for( size_type i = 1; i <= vs_rhs.dim(); ++i )
      sv_lhs->add_element( ele_t( i + offset, alpha * (*itr++) ) );
  }
  else {
    for( size_type i = 1; i <= vs_rhs.dim(); ++i, ++itr )
      if( *itr != 0.0 )
        sv_lhs->add_element( ele_t( i + offset, alpha * (*itr) ) );
  }
  sv_lhs->assume_sorted(assume_sorted);
}
void MatrixSymDiagStd::V_InvMtV(
  DVectorSlice* vs_lhs, BLAS_Cpp::Transp trans_rhs1
  , const DVectorSlice& vs_rhs2) const
{
  const DVectorSlice diag = this->diag();
  size_type n = diag.size();

  // y = inv(op(A)) * x
  //
  // A is symmetric and diagonal (A = diag(diag)) so:
  //
  // y(j) = x(j) / diag(j), for j = 1...n

  DenseLinAlgPack::Vp_MtV_assert_sizes( vs_lhs->size()
    , n, n, trans_rhs1, vs_rhs2.size() );
  
  if( vs_rhs2.stride() == 1 && vs_lhs->stride() == 1 ) {
    // Optimized implementation
    const value_type
      *d_itr      = diag.raw_ptr(),
      *x_itr      = vs_rhs2.raw_ptr();
    value_type
      *y_itr      = vs_lhs->raw_ptr(),
      *y_end      = y_itr + vs_lhs->size();
    while( y_itr != y_end )
      *y_itr++ = (*x_itr++) / (*d_itr++);
  }
  else {
    // Generic implementation
    DVectorSlice::const_iterator
      d_itr = diag.begin(),
      x_itr = vs_rhs2.begin();
    DVectorSlice::iterator
      y_itr = vs_lhs->begin(),
      y_end = vs_lhs->end();
    for( ; y_itr != y_end; ++y_itr, ++d_itr, ++x_itr ) {
      TEST_FOR_EXCEPT( !(  d_itr < diag.end()  ) );
      TEST_FOR_EXCEPT( !(  x_itr < vs_rhs2.end()  ) );
      TEST_FOR_EXCEPT( !(  y_itr < vs_lhs->end()  ) );
      *y_itr = (*x_itr)/(*d_itr);
    }
  }
}
void DenseLinAlgPack::V_InvMtV(DVectorSlice* vs_lhs, const DMatrixSliceTri& tri_rhs1, BLAS_Cpp::Transp trans_rhs1
  , const DVectorSlice& vs_rhs2)
{
  assert_gms_square(tri_rhs1.gms());
  MtV_assert_sizes(tri_rhs1.gms().rows(), tri_rhs1.gms().cols(), trans_rhs1, vs_rhs2.dim());
  Vp_V_assert_sizes( vs_lhs->dim(), tri_rhs1.gms().rows() );
  (*vs_lhs) = vs_rhs2;
  BLAS_Cpp::trsv(tri_rhs1.uplo(),trans_rhs1,tri_rhs1.diag(),tri_rhs1.gms().rows()
    ,tri_rhs1.gms().col_ptr(1),tri_rhs1.gms().max_rows(), vs_lhs->raw_ptr(),vs_lhs->stride());
}
void DenseLinAlgPack::ger(
  value_type alpha, const DVectorSlice& vs_rhs1, const DVectorSlice& vs_rhs2
  , DMatrixSlice* gms_lhs )
{
  Vp_MtV_assert_sizes( vs_rhs2.dim(),  gms_lhs->rows(), gms_lhs->cols()
    , BLAS_Cpp::no_trans, vs_rhs1.dim() );
  BLAS_Cpp::ger(
    gms_lhs->rows(), gms_lhs->cols(), alpha
    ,vs_rhs1.raw_ptr(), vs_rhs1.stride()
    ,vs_rhs2.raw_ptr(), vs_rhs2.stride()
    ,gms_lhs->col_ptr(1), gms_lhs->max_rows() );
}
void DenseLinAlgPack::Vp_StMtV(DVectorSlice* vs_lhs, value_type alpha, const DMatrixSliceTri& tri_rhs1
  , BLAS_Cpp::Transp trans_rhs1, const DVectorSlice& vs_rhs2, value_type beta)
{
  Vp_MtV_assert_sizes(vs_lhs->dim(),tri_rhs1.gms().rows(),tri_rhs1.gms().cols()
            ,trans_rhs1,vs_rhs2.dim() );

  // If op(gms_rhs2) == gms_lhs and beta = 0.0 then this is a direct call to the BLAS.
  if( vs_lhs->overlap(vs_rhs2) == SAME_MEM && beta == 0.0 )
  {
    V_MtV(vs_lhs, tri_rhs1, trans_rhs1, vs_rhs2);
    if(alpha != 1.0) Vt_S(vs_lhs,alpha);
  }
  else {
    // This is something else so the alias problem is not handled.
    if(beta != 1.0) Vt_S(vs_lhs,beta);
    DVector tmp;
    V_MtV(&tmp, tri_rhs1, trans_rhs1, vs_rhs2);
    Vp_StV(vs_lhs,alpha,tmp());
  }
}
void MatrixHessianRelaxed::Vp_StMtV(
    DVectorSlice* y, value_type a, BLAS_Cpp::Transp M_trans
  , const DVectorSlice& x, value_type b ) const
{
  using BLAS_Cpp::no_trans;
  using BLAS_Cpp::trans;
  using AbstractLinAlgPack::Vp_StMtV;
  //
  // y = b*y + a * M * x
  // 
  //   = b*y + a * [ H  0    ] * [ x1 ]
  //               [ 0  bigM ]   [ x2 ]
  //               
  // =>              
  //               
  // y1 = b*y1 + a*H*x1
  // 
  // y2 = b*y2 + bigM * x2
  //
  LinAlgOpPack::Vp_MtV_assert_sizes(y->size(),rows(),cols(),M_trans,x.size());

  DVectorSlice
    y1 = (*y)(1,n_);
  value_type
    &y2 = (*y)(n_+1);
  const DVectorSlice
    x1 = x(1,n_);
  const value_type
    x2 = x(n_+1);

  // y1 = b*y1 + a*H*x1
  Vp_StMtV( &y1, a, *H_, no_trans, x1, b );

  // y2 = b*y2 + bigM * x2
  if( b == 0.0 )
    y2 = bigM_ * x2;
  else
    y2 = b*y2 + bigM_ * x2;
  
}
QPSolverStats::ESolutionType
QPSolverRelaxedLOQO::imp_solve_qp(
      std::ostream* out, EOutputLevel olevel, ERunTests test_what
    , const DVectorSlice& g, const MatrixOp& G
    , value_type etaL
    , const SpVectorSlice& dL, const SpVectorSlice& dU
    , const MatrixOp* E, BLAS_Cpp::Transp trans_E, const DVectorSlice* b
      , const SpVectorSlice* eL, const SpVectorSlice* eU
    , const MatrixOp* F, BLAS_Cpp::Transp trans_F, const DVectorSlice* f
    , value_type* obj_d
    , value_type* eta, DVectorSlice* d
    , SpVector* nu
    , SpVector* mu, DVectorSlice* Ed
    , DVectorSlice* lambda, DVectorSlice* Fd
  )
{
  using Teuchos::Workspace;
  Teuchos::WorkspaceStore* wss = wsp::default_workspace_store.get();

  const value_type inf_bnd  = std::numeric_limits<value_type>::max();
//	const value_type real_big = 1e+20;
  const value_type real_big = HUGE_VAL;

  const size_type
    nd   = g.size(),
    m_in = E ? b->size() : 0,
    m_eq = F ? f->size() : 0;

  //
  // Create a LOQO QP definition struct
  //

  LOQO *loqo_lp = openlp();
  TEUCHOS_TEST_FOR_EXCEPT( !(  loqo_lp  ) );

  //
  // Setup loqo_r and loqo_b and count the number of actual
  // constraints.
  //

  // LOQO's b vector storage
  MALLOC( loqo_lp->b, m_in+m_eq, double ); // May not use all of this storage
  DVectorSlice loqo_b( loqo_lp->b, m_in+m_eq );
  // LOQO's r vector storage
  MALLOC( loqo_lp->r, m_in+m_eq, double ); // May not use all of this storage
  DVectorSlice loqo_r( loqo_lp->r, m_in+m_eq );
  // Gives status of b.
  //                  /  j : if eL(j) > -inf_bnd
  // loqo_b_stat(k) = |
  //                  \ -j : if eL(j) <= -inf_bnd && eU(j) < +inf_bnd
  //
  // , for k = 1...num_inequal
  //
  Workspace<int>               loqo_b_stat_ws(wss,m_in); // May not use all of this
  DenseLinAlgPack::VectorSliceTmpl<int>  loqo_b_stat(&loqo_b_stat_ws[0],loqo_b_stat_ws.size());
  std::fill( loqo_b_stat.begin(), loqo_b_stat.end(), 0 ); // Initialize to zero

  // Fill up loqo_b, loqo_r and loqo_b_stat
  size_type num_inequal = 0; // The actual number of bouned general inequalities
  if(E) {
    // Read iterators
    AbstractLinAlgPack::sparse_bounds_itr
      eLU_itr( eL->begin(), eL->end(), eL->offset()
           , eU->begin(), eU->end(), eU->offset(), inf_bnd );
    // written iterators
    DVectorSlice::iterator
      b_itr		= loqo_b.begin(),
      r_itr		= loqo_r.begin();
    DenseLinAlgPack::VectorSliceTmpl<int>::iterator
      b_stat_itr  = loqo_b_stat.begin();
    // loop
    for( int k = 1; !eLU_itr.at_end(); ++k, ++eLU_itr, ++b_itr, ++r_itr, ++b_stat_itr, ++num_inequal )
    {
      const size_type j = eLU_itr.indice();
      if(eLU_itr.lbound() > -inf_bnd) {
        *b_itr = eLU_itr.lbound();
        *r_itr = eLU_itr.ubound() >= inf_bnd ? real_big : eLU_itr.ubound() - eLU_itr.lbound();
        *b_stat_itr = j; // We need to make A(k,:) = [ +op(E)(j,:), -b(j) ]
      }
      else {
        TEUCHOS_TEST_FOR_EXCEPT( !( eLU_itr.ubound() < +inf_bnd ) );
        *b_itr = -eLU_itr.ubound();
        *r_itr = eLU_itr.lbound() <= -inf_bnd ? real_big : - eLU_itr.lbound() + eLU_itr.ubound();
        *b_stat_itr = -j; // We need to make A(k,:) = [ -op(E)(j,:), +b(j) ]
      }
    }
  }
  if(F) {
    LinAlgOpPack::V_StV( &loqo_b(num_inequal+1,num_inequal+m_eq), -1.0, *f );
    loqo_r(num_inequal+1,num_inequal+m_eq) = 0.0;
  }

  //
  // Setup the QP dimensions
  //

  loqo_lp->n = nd+1;
  loqo_lp->m = num_inequal + m_eq;

  //
  // Setup loqo_c, loqo_l and loqo_u
  //

  // LOQO's c vector storage
  MALLOC( loqo_lp->c, nd+1, double );
  DVectorSlice loqo_c( loqo_lp->c, nd+1 );
  loqo_c(1,nd) = g;
  loqo_c(nd+1) = bigM();

  // LOQO's l vector storage
  MALLOC( loqo_lp->l, nd+1, double );
  DVectorSlice loqo_l( loqo_lp->l, nd+1 );
  std::fill( loqo_l.begin(), loqo_l.end(), -real_big );
  {
    SpVectorSlice::const_iterator
      dL_itr = dL.begin(),
      dL_end = dL.end();
    for( ; dL_itr != dL_end; ++dL_itr )
      loqo_l( dL_itr->indice() + dL.offset() ) = dL_itr->value();
  }
  loqo_l(nd+1) = etaL;

  // LOQO's u vector storage
  MALLOC( loqo_lp->u, nd+1, double );
  DVectorSlice loqo_u( loqo_lp->u, nd+1 );
  std::fill( loqo_u.begin(), loqo_u.end(), +real_big );
  {
    SpVectorSlice::const_iterator
      dU_itr = dU.begin(),
      dU_end = dU.end();
    for( ; dU_itr != dU_end; ++dU_itr )
      loqo_u( dU_itr->indice() + dU.offset() ) = dU_itr->value();
  }
  loqo_u(nd+1) = +real_big;
  
  //
  // Setup the objective and constraint matrices (using strategy interface).
  //

  init_hess_jacob().init_hess_jacob(
    G,bigM(),E,trans_E,b,&loqo_b_stat[0],num_inequal,F,trans_F,f
    ,loqo_lp);

  //
  // Setup the starting point
  //

  MALLOC( loqo_lp->x, nd+1, double );
  DVectorSlice loqo_x( loqo_lp->x, nd+1 );
  loqo_x(1,nd) = *d;
  loqo_x(nd+1) = *eta;

  //
  // Set some control parameters
  //
  
//	strcpy( loqo_lp->name, "loqo_qp" );
  loqo_lp->quadratic = 1;
  loqo_lp->convex    = 1;
  switch( olevel ) {
    case PRINT_NONE:
      loqo_lp->verbose = 0;
      break;
    case PRINT_BASIC_INFO:
      loqo_lp->verbose = 1;
      break;
    case PRINT_ITER_SUMMARY:
      loqo_lp->verbose = 2;
      break;
    case PRINT_ITER_STEPS:
      loqo_lp->verbose = 3;
      break;
    case PRINT_ITER_ACT_SET:
      loqo_lp->verbose = 4;
      break;
    case PRINT_ITER_VECTORS:
      loqo_lp->verbose = 5;
      break;
    case PRINT_EVERY_THING:
      loqo_lp->verbose = 6;
      break;
    default:
      TEUCHOS_TEST_FOR_EXCEPT(true);
  }

  //
  // Solve the QP
  //

  if( out && olevel >= PRINT_BASIC_INFO ) {
    *out << "\nSolving QP using LOQO ...\n";
    out->flush();
  }
  
  const int loqo_status = solvelp(loqo_lp);

  if( out && olevel >= PRINT_BASIC_INFO ) {
    *out << "\nLOQO returned status = " << loqo_status << "\n";
  }

  //
  // Map the solution to the output arguments
  //

  TEUCHOS_TEST_FOR_EXCEPT( !(  loqo_lp->x  ) );
  DVectorSlice loqo_x_sol( loqo_lp->x, nd+1 );

  // d
  *d    = loqo_x_sol(1,nd);

  // eta
  *eta  = loqo_x_sol(nd+1);

  // obj_d
  if(obj_d)
    *obj_d = loqo_lp->primal_obj - (*eta + 0.5 * (*eta)*(*eta)) * bigM();

  // nu
  if(nu) {
    nu->resize(nd,nd);
    TEUCHOS_TEST_FOR_EXCEPT( !(  loqo_lp->z  ) );
    TEUCHOS_TEST_FOR_EXCEPT( !(  loqo_lp->s  ) );
    const DVectorSlice
      loqo_z(loqo_lp->z,loqo_lp->n),   // Multipliers for l - x <= 0
      loqo_s(loqo_lp->s,loqo_lp->n);   // Multipliers for x - u <= 0
    DVectorSlice::const_iterator
      z_itr = loqo_z.begin(),
      s_itr = loqo_s.begin();
    typedef SpVector::element_type ele_t;
    for( size_type i = 1; i <= nd; ++i, ++z_itr, ++s_itr ) {
      if( *z_itr > *s_itr && *z_itr >= nonbinding_lag_mult() ) {
        // Lower bound is active
        nu->add_element(ele_t(i,-(*z_itr)));
      }
      else if( *s_itr > *z_itr && *s_itr >= nonbinding_lag_mult() ) {
        // Upper bound is active
        nu->add_element(ele_t(i,+(*s_itr)));
      }
    }
    // We could look at z(nd+1) and s(nd+1) for the value of kappa?
    nu->assume_sorted(true);
  }

  // mu
  if(mu) {
    mu->resize(m_in,num_inequal);
    DenseLinAlgPack::VectorSliceTmpl<int>::iterator
      b_stat_itr  = loqo_b_stat.begin();
    TEUCHOS_TEST_FOR_EXCEPT( !(  loqo_lp->v  ) );
    TEUCHOS_TEST_FOR_EXCEPT( !(  loqo_lp->q  ) );
    const DVectorSlice
      loqo_v(loqo_lp->v,loqo_lp->m),   // Multipliers for b <= A*x
      loqo_q(loqo_lp->q,loqo_lp->m);   // Multipliers for A*x <= b + r
    DVectorSlice::const_iterator
      v_itr = loqo_v.begin(),
      q_itr = loqo_q.begin();
    // loop
    typedef SpVector::element_type ele_t;
    for( size_type k = 1; k <= num_inequal; ++k, ++b_stat_itr, ++v_itr, ++q_itr ) {
      const int j = *b_stat_itr;
      if( *v_itr > *q_itr && *v_itr >= nonbinding_lag_mult() ) {
        // Lower bound is active
        if( j < 0 ) // We had to flip this since it was really and upper bound
          mu->add_element(ele_t(-j,+(*v_itr)));
        else // This really was a lower bound
          mu->add_element(ele_t(+j,-(*v_itr)));
      }
      else if( *q_itr > *v_itr && *q_itr >= nonbinding_lag_mult() ) {
        // Upper bound is active
        mu->add_element(ele_t(+j,+(*q_itr)));
      }
    }
  }

  // Ed
  if(Ed) {
    LinAlgOpPack::V_MtV( Ed, *E, trans_E, *d );
  }

  // lambda
  if(lambda) {
    TEUCHOS_TEST_FOR_EXCEPT( !(  loqo_lp->y  ) );
    const DVectorSlice
      loqo_y(loqo_lp->y,loqo_lp->m);         // Multipliers for equalities
    DVectorSlice::const_iterator
      y_itr = loqo_y.begin() + num_inequal;  // Get iterators to equalities
    DVectorSlice::iterator
      lambda_itr = lambda->begin();
    // loop
    for( size_type k = 1; k <= m_eq; ++k, ++y_itr, ++lambda_itr ) {
      *lambda_itr = -(*y_itr);
    }
  }

  // Fd
  if(Fd) {
    LinAlgOpPack::V_MtV( Fd, *F, trans_F, *d );
  }

  //
  // Setup the QP statistics
  //

  QPSolverStats::ESolutionType solution_type = QPSolverStats::OPTIMAL_SOLUTION; // Assume this?
  switch( loqo_status ) { // I had to find this out by trial and error!
      case 0:
      solution_type = QPSolverStats::OPTIMAL_SOLUTION;
      break;
    case 2:
      solution_type = QPSolverStats::DUAL_FEASIBLE_POINT;
      break;
    default:
      TEUCHOS_TEST_FOR_EXCEPT(true);
  }

  qp_stats_.set_stats(
    solution_type, QPSolverStats::CONVEX
    ,loqo_lp->iter, QPSolverStats::NOT_KNOWN, QPSolverStats::NOT_KNOWN
    ,false, *eta > 0.0 );

  //
  // Clean up dynamically allocated memory for LOQO
  //

  inv_clo();          // frees memory associated with matrix factorization
  closelp(loqo_lp);   // frees all allocated arrays with free(...).

  return qp_stats_.solution_type();

}
void QPInitFixedFreeStd::initialize(
    const DVectorSlice                   &g
    ,const MatrixSymOp              &G
    ,const MatrixOp                 *A
    ,size_type                          n_R
    ,const size_type                    i_x_free[]
    ,const size_type                    i_x_fixed[]
    ,const EBounds                      bnd_fixed[]
    ,const DVectorSlice                  &b_X
    ,const MatrixSymOpNonsing    &Ko
    ,const DVectorSlice                  &fo
    ,Constraints                        *constraints
    ,std::ostream                       *out
    ,bool                               test_setup
    ,value_type                         warning_tol
    ,value_type                         error_tol
    ,bool                               print_all_warnings
)
{
    namespace GPMSTP = AbstractLinAlgPack::GenPermMatrixSliceIteratorPack;

    if(!constraints)
        throw std::invalid_argument( "QPInitFixedFreeStd::initialize(...) : Error, "
                                     "constraints == NULL is not allowed." );

    // Validate the sizes of the input arguments
    const size_type
    n = constraints->n(),
    n_X = n - n_R;
    if( n_R > n )
        throw std::invalid_argument( "QPInitFixedFreeStd::initialize(...) : Error, "
                                     "n_R > constraints->n() is not allowed." );
    if(g.dim() !=n)
        throw std::invalid_argument( "QPInitFixedFreeStd::initialize(...) : Error, "
                                     "g.dim() != constraints->n()." );
    if(G.rows() != n || G.cols() !=  n)
        throw std::invalid_argument( "QPInitFixedFreeStd::initialize(...) : Error, "
                                     "G.rows() != constraints->n() or G.cols() !=  constraints->n()." );
    size_type
    m = 0;
    if(A) {
        m = A->cols();
        if( A->rows() != n )
            throw std::invalid_argument( "QPInitFixedFreeStd::initialize(...) : Error, "
                                         "A->rows() != constraints->n()." );
    }
    if(b_X.dim() != n_X)
        throw std::invalid_argument( "QPInitFixedFreeStd::initialize(...) : Error, "
                                     "b_X.dim() != constraints->n() - n_R." );
    if(Ko.rows() != n_R+m || Ko.cols() !=  n_R+m)
        throw std::invalid_argument( "QPInitFixedFreeStd::initialize(...) : Error, "
                                     "Ko.rows() != n_R+A->cols() or Ko.cols() !=  n_R+A->cols()." );
    if(fo.dim() != n_R+m)
        throw std::invalid_argument( "QPInitFixedFreeStd::initialize(...) : Error, "
                                     "fo.dim() != n_R+A->cols()." );

    // Setup x_init, l_x_X_map, i_x_X_map

    const int NOT_SET_YET = -9999; // Can't be FREE, LOWER, UPPER, or EQUALITY
    if(test_setup)
        x_init_.assign( n, (EBounds)NOT_SET_YET );
    else
        x_init_.resize(n);
    l_x_X_map_.assign(n,0);
    i_x_X_map_.assign(n_X,0);

    // Set free portion of x_init
    if( i_x_free == NULL ) {
        for( size_type i = 0; i < n_R; ++i )
            x_init_[i] = FREE;
    }
    else {
        if(test_setup) {
            for( const size_type *i_x_R = i_x_free; i_x_R != i_x_free + n_R; ++i_x_R ) {
                if( *i_x_R < 1 || *i_x_R > n ) {
                    std::ostringstream omsg;
                    omsg
                            << "QPInitFixedFreeStd::initialize(...) : Error, "
                            << "i_x_free[" << i_x_R-i_x_free << "] = "
                            << (*i_x_R) << " is out of bounds";
                    throw std::invalid_argument( omsg.str() );
                }
                if( x_init_(*i_x_R) != NOT_SET_YET ) {
                    std::ostringstream omsg;
                    omsg
                            << "QPInitFixedFreeStd::initialize(...) : Error, "
                            << "Duplicate entries for i_x_free[i] = "
                            << (*i_x_R);
                    throw std::invalid_argument( omsg.str() );
                }
                x_init_(*i_x_R) = FREE;
            }
        }
        else {
            for( const size_type *i_x_R = i_x_free; i_x_R != i_x_free + n_R; ++i_x_R ) {
                x_init_(*i_x_R) = FREE;
            }
        }
    }

    // Setup the fixed portion of x_init and l_x_X_map and i_x_X_map
    {
        const size_type
        *i_x_X = i_x_fixed;
        const EBounds
        *bnd = bnd_fixed;
        i_x_X_map_t::iterator
        i_x_X_map_itr = i_x_X_map_.begin();
        if(test_setup) {
            for( size_type l = 1; l <= n_X; ++l, ++i_x_X, ++bnd, ++i_x_X_map_itr ) {
                if( *i_x_X < 1 || *i_x_X > n ) {
                    std::ostringstream omsg;
                    omsg
                            << "QPInitFixedFreeStd::initialize(...) : Error, "
                            << "i_x_fixed[" << i_x_X-i_x_fixed << "] = "
                            << (*i_x_X) << " is out of bounds";
                    throw std::invalid_argument( omsg.str() );
                }
                if( *bnd == FREE ) {
                    std::ostringstream omsg;
                    omsg
                            << "QPInitFixedFreeStd::initialize(...) : Error, "
                            << "bnd_fixed[" << l-1 << "] can not equal FREE";
                    throw std::invalid_argument( omsg.str() );
                }
                if( x_init_(*i_x_X) != NOT_SET_YET ) {
                    std::ostringstream omsg;
                    omsg
                            << "QPInitFixedFreeStd::initialize(...) : Error, "
                            << "Duplicate entries for i_x_fixed[i] = "
                            << (*i_x_X);
                    throw std::invalid_argument( omsg.str() );
                }
                x_init_(*i_x_X) = *bnd;
                l_x_X_map_(*i_x_X) = l;
                *i_x_X_map_itr = *i_x_X;
            }
            // Check that x_init was filled up properly
            for( size_type i = 1; i <= n; ++i ) {
                if( x_init_(i) == NOT_SET_YET ) {
                    std::ostringstream omsg;
                    omsg
                            << "QPInitFixedFreeStd::initialize(...) : Error, "
                            << "x_init(" << i << ") has not been set by"
                            " i_x_free[] or i_x_fixed[].";
                    throw std::invalid_argument( omsg.str() );
                }
            }
        }
        else {
            for( size_type l = 1; l <= n_X; ++l, ++i_x_X, ++bnd, ++i_x_X_map_itr ) {
                x_init_(*i_x_X) = *bnd;
                l_x_X_map_(*i_x_X) = l;
                *i_x_X_map_itr = *i_x_X;
            }
        }
    }

    // Setup Q_R and Q_X
    Q_R_row_i_.resize( i_x_free ? n_R : 0 );
    Q_R_col_j_.resize( i_x_free ? n_R : 0 );
    Q_X_row_i_.resize(n_X);
    Q_X_col_j_.resize(n_X);
    initialize_Q_R_Q_X(
        n_R,n_X,i_x_free,i_x_fixed,test_setup
        ,n_R && i_x_free ? &Q_R_row_i_[0] : NULL
        ,n_R && i_x_free ? &Q_R_col_j_[0] : NULL
        ,&Q_R_
        ,n_X ? &Q_X_row_i_[0] : NULL
        ,n_X ? &Q_X_col_j_[0] : NULL
        ,&Q_X_
    );

    // Setup other arguments
    n_				= n;
    n_R_			= n_R;
    m_				= m;
    g_.bind(const_cast<DVectorSlice&>(g));
    G_				= &G;
    A_				= A;
    b_X_.bind(const_cast<DVectorSlice&>(b_X));
    Ko_				= &Ko;
    fo_.bind(const_cast<DVectorSlice&>(fo));
    constraints_ 	= constraints;
}
void QPSchurInitKKTSystemHessianRelaxed::initialize_kkt_system(
    const DVectorSlice&    g
    ,const MatrixOp&  G
    ,value_type           etaL
    ,const SpVectorSlice& dL
    ,const SpVectorSlice& dU
    ,const MatrixOp*  F
    ,BLAS_Cpp::Transp     trans_F
    ,const DVectorSlice*   f
    ,const DVectorSlice&   d
    ,const SpVectorSlice& nu
    ,size_type*           n_R
    ,i_x_free_t*          i_x_free
    ,i_x_fixed_t*         i_x_fixed
    ,bnd_fixed_t*         bnd_fixed
    ,j_f_decomp_t*        j_f_decomp
    ,DVector*              b_X
    ,Ko_ptr_t*            Ko
    ,DVector*              fo
) const
{
    using BLAS_Cpp::trans;

    // Validate type of and convert G
    const MatrixSymHessianRelaxNonSing
    *G_relax_ptr = dynamic_cast<const MatrixSymHessianRelaxNonSing*>(&G);

    if( G_relax_ptr == NULL ) {
        init_kkt_full_.initialize_kkt_system(
            g,G,etaL,dL,dU,F,trans_F,f,d,nu,n_R,i_x_free,i_x_fixed,bnd_fixed
            ,j_f_decomp,b_X,Ko,fo);
        return;
    }

    const MatrixSymHessianRelaxNonSing
    &G_relax = *G_relax_ptr;

    // get some stuff
    const MatrixSymWithOpFactorized
    &G_orig = G_relax.G(),
     &M      = G_relax.M();
    const size_type
    nd = g.size(),
    no = G_orig.rows(),
    nr = M.rows();
    TEST_FOR_EXCEPT( !(  no + nr == nd  ) );

    // Setup output arguments

    // n_R = nd_R
    *n_R = no;
    // i_x_free.size() == 0 and i_x_free is implicitly identity
    i_x_free->resize(no);
{   for(size_type l = 1; l <= no; ++l ) {
            (*i_x_free)[l-1] = l;
        }
    }
    // i_x_fixed[]
    i_x_fixed->resize(nr+1);
    if(nr) {
        // i_x_fixed[l-1] = no + l, l = 1...nr
        for( size_type l = 1; l <= nr; ++l )
            (*i_x_fixed)[l-1] = no+l;
    }
    (*i_x_fixed)[nr] = nd+1; // extra relaxation is always initially active
    // bnd_fixed[]
    bnd_fixed->resize(nr+1);
    if(nr) {
        // bnd_fixed[l-1] = LOWER, l = 1...nr
        std::fill_n( bnd_fixed->begin(), nr, LOWER );
    }
    (*bnd_fixed)[nr] = LOWER; // relaxation is always initially active
    // j_f_decomp[]
    j_f_decomp->resize(0);
    // b_X
    b_X->resize(nr+1);
    if(nr) {
        // b_X[l-1] = dL(no+l), l = 1...nr
        LinAlgOpPack::assign( &(*b_X)(1,nr), dL(no+1,no+nr) );
    }
    (*b_X)[nr] = etaL; // relaxation is always initially active
    // Ko = G.G
    *Ko = G_relax.G_ptr(); // now B_RR is a shared object
    // fo = - *g(1:no)
    LinAlgOpPack::V_StV( fo, -1.0, g(1,no) );

}
void MatrixSymIdentitySerial::V_InvMtV(
  DVectorSlice* y, BLAS_Cpp::Transp M_trans, const DVectorSlice& x
  ) const
{
  DenseLinAlgPack::Vp_MtV_assert_sizes( y->dim(), rows(), cols(), BLAS_Cpp::no_trans, x.dim() );
  LinAlgOpPack::V_StV(y,scale_,x);
}
void MatrixSymIdentitySerial::Vp_StMtV(
  DVectorSlice* y, value_type a, BLAS_Cpp::Transp M_trans
  ,const DVectorSlice& x, value_type b
  ) const
{
  DenseLinAlgPack::Vp_MtV_assert_sizes( y->dim(), rows(), cols(), BLAS_Cpp::no_trans, x.dim() );
  DenseLinAlgPack::Vt_S(y,b);
  DenseLinAlgPack::Vp_StV(y,a*scale_,x);
}
bool DenseLinAlgPack::comp(const DVectorSlice& vs, value_type alpha) {
  DVectorSlice::const_iterator vs_itr = vs.begin();
  for(; vs_itr != vs.end(); ++vs_itr)
    if( !_comp(*vs_itr,alpha) ) return false;
  return true;
}
void MatrixHessianRelaxed::Vp_StPtMtV(
  DVectorSlice* y, value_type a
  , const GenPermMatrixSlice& P, BLAS_Cpp::Transp P_trans
  , BLAS_Cpp::Transp M_trans
  , const DVectorSlice& x, value_type b ) const
{
  using BLAS_Cpp::no_trans;
  using BLAS_Cpp::trans;
  namespace GPMSIP = AbstractLinAlgPack::GenPermMatrixSliceIteratorPack;
  //
  // y = b*y + a * op(P) * M * x
  // 
  //   = b*y + a * [ op(P1)  op(P2) ] *  [ H   0   ] * [ x1 ]
  //                                     [ 0  bigM ]   [ x2 ]
  //               
  // =>              
  //               
  // y = b*y + a*op(P1)*H*x1 + a*op(P2)*bigM*x2
  //
  LinAlgOpPack::Vp_MtV_assert_sizes(y->size(),P.rows(),P.cols(),P_trans
    , BLAS_Cpp::rows( rows(), cols(), M_trans) );
  LinAlgOpPack::Vp_MtV_assert_sizes( BLAS_Cpp::cols( P.rows(), P.cols(), P_trans)
    ,rows(),cols(),M_trans,x.size());

  // For this to work (as shown below) we need to have P sorted by
  // row if op(P) = P' or sorted by column if op(P) = P.  If
  // P is not sorted properly, we will just use the default
  // implementation of this operation.
  if( 	( P.ordered_by() == GPMSIP::BY_ROW && P_trans == no_trans )
      || 	( P.ordered_by() == GPMSIP::BY_COL && P_trans == trans ) )
  {
    // Call the default implementation
    MatrixOp::Vp_StPtMtV(y,a,P,P_trans,M_trans,x,b);
    return;
  }

  if( P.is_identity() )
    TEUCHOS_TEST_FOR_EXCEPT( !(  BLAS_Cpp::rows( P.rows(), P.cols(), P_trans ) == n_  ) );

  const GenPermMatrixSlice
    P1 = ( P.is_identity() 
         ? GenPermMatrixSlice( n_, n_, GenPermMatrixSlice::IDENTITY_MATRIX )
         : P.create_submatrix(Range1D(1,n_),P_trans==trans?GPMSIP::BY_ROW:GPMSIP::BY_COL)
      ),
    P2 = ( P.is_identity()
         ? GenPermMatrixSlice(
           P_trans == no_trans ? n_ : 1
           , P_trans == no_trans ? 1 : n_
           , GenPermMatrixSlice::ZERO_MATRIX )
         : P.create_submatrix(Range1D(n_+1,n_+1),P_trans==trans?GPMSIP::BY_ROW:GPMSIP::BY_COL)
      );
  
  const DVectorSlice
    x1 = x(1,n_);
  const value_type
    x2 = x(n_+1);
  // y = b*y + a*op(P1)*H*x1
  AbstractLinAlgPack::Vp_StPtMtV( y, a, P1, P_trans, *H_, no_trans, x1, b );
  // y += a*op(P2)*bigM*x2
  if( P2.nz() ){
    TEUCHOS_TEST_FOR_EXCEPT( !( P2.nz() == 1 ) );
    const size_type
      i = P_trans == no_trans ? P2.begin()->row_i() : P2.begin()->col_j();
    (*y)(i) += a * bigM_ * x2;
  }
}
bool MeritFunc_PenaltyParamsUpdateWithMult_AddedStep::do_step(Algorithm& _algo
  , poss_type step_poss, IterationPack::EDoStepType type
  , poss_type assoc_step_poss)
{
  using DenseLinAlgPack::norm_inf;

  NLPAlgo	&algo	= rsqp_algo(_algo);
  NLPAlgoState	&s		= algo.rsqp_state();
  
  EJournalOutputLevel olevel = algo.algo_cntr().journal_output_level();
  std::ostream& out = algo.track().journal_out();

  // print step header.
  if( static_cast<int>(olevel) >= static_cast<int>(PRINT_ALGORITHM_STEPS) ) {
    using IterationPack::print_algorithm_step;
    print_algorithm_step( algo, step_poss, type, assoc_step_poss, out );
  }

  MeritFuncPenaltyParams
    *params = dynamic_cast<MeritFuncPenaltyParams*>(&merit_func());
  if( !params ) {
    std::ostringstream omsg;
    omsg
      << "MeritFunc_PenaltyParamsUpdateWithMult_AddedStep::do_step(...), Error "
      << "The class " << typeName(&merit_func()) << " does not support the "
      << "MeritFuncPenaltyParams iterface\n";
    out << omsg.str();
    throw std::logic_error( omsg.str() );
  }

  MeritFuncNLPDirecDeriv
    *direc_deriv = dynamic_cast<MeritFuncNLPDirecDeriv*>(&merit_func());
  if( !direc_deriv ) {
    std::ostringstream omsg;
    omsg
      << "MeritFunc_PenaltyParamsUpdateWithMult_AddedStep::do_step(...), Error "
      << "The class " << typeName(&merit_func()) << " does not support the "
      << "MeritFuncNLPDirecDeriv iterface\n";
    out << omsg.str();
    throw std::logic_error( omsg.str() );
  }

  bool perform_update = true;

  if( s.mu().updated_k(0) ) {
    if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) {
      out << "\nmu_k is already updated by someone else?\n";
    }
    const value_type mu_k = s.mu().get_k(0);
    if( mu_k == norm_inf_mu_last_ ) {
      if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) {
        out << "\nmu_k " << mu_k << " == norm_inf_mu_last = " << norm_inf_mu_last_
          << "\nso we will take this as a signal to skip the update.\n";
      }
      perform_update = false;
    }
    else {
      if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) {
        out << "\nmu_k " << mu_k << " != norm_inf_mu_last = " << norm_inf_mu_last_
          << "\nso we will ignore this and perform the update anyway.\n";
      }
    }		
  }
  if(perform_update) {

    if ( s.lambda().updated_k(0) ) {

      if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) {
        out << "\nUpdate the penalty parameter...\n";
      }

      const DVector
        &lambda_k = s.lambda().get_k(0).cv();

      if( params->mu().size() != lambda_k.size() )
        params->resize( lambda_k.size() );
      DVectorSlice
        mu = params->mu();

      const value_type
        max_lambda	= norm_inf( lambda_k() ),
        mult_fact	= (1.0 + mult_factor_);

      if(near_solution_) {
        if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) {
          out << "\nNear solution, forcing mu(j) >= mu_old(j)...\n";
        }
        DVector::const_iterator	lb_itr = lambda_k.begin();
        DVectorSlice::iterator	mu_itr = mu.begin();
        for( ; lb_itr != lambda_k.end(); ++mu_itr, ++ lb_itr )
          *mu_itr = max( max( *mu_itr, mult_fact * ::fabs(*lb_itr) ), small_mu_ );
      }
      else {
        if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) {
          out << "\nNot near solution, allowing reduction in mu(j) ...\n";
        }
        DVector::const_iterator	lb_itr = lambda_k.begin();
        DVectorSlice::iterator	mu_itr = mu.begin();
        for( ; lb_itr != lambda_k.end(); ++mu_itr, ++ lb_itr ) {
          const value_type lb_j = ::fabs(*lb_itr);
          *mu_itr = max(
                  (3.0 * (*mu_itr) + lb_j) / 4.0	
                , max( mult_fact * lb_j, small_mu_ )
                );
        }
        value_type kkt_error = s.opt_kkt_err().get_k(0) + s.feas_kkt_err().get_k(0);
        if(kkt_error <= kkt_near_sol_) {
          if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) {
            out << "\nkkt_error = " << kkt_error << " <= kkt_near_sol = "
                << kkt_near_sol_ << std::endl
              << "Switching to forcing mu_k >= mu_km1 in the future\n";
          }
          near_solution_ = true;
        }
      }

      // Force the ratio
      const value_type
          max_mu	= norm_inf( mu() ),
          min_mu	= min_mu_ratio_ * max_mu;
      for(DVectorSlice::iterator mu_itr = mu.begin(); mu_itr != mu.end(); ++mu_itr)
        *mu_itr = max( (*mu_itr), min_mu );	

      s.mu().set_k(0) = norm_inf_mu_last_ = max_mu;

      if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) {
        out << "\nmax(|mu(j)|) = " << (*std::max_element( mu.begin(), mu.end() ))
          << "\nmin(|mu(j)|) = " << (*std::min_element( mu.begin(), mu.end() ))
            << std::endl;
      }

      if( (int)olevel >= (int)PRINT_VECTORS ) {
        out << "\nmu = \n" << mu;
      }
    }
    else {
      if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) {
        out << "\nDon't have the info to update penalty parameter so just use the last updated...\n";
      }
    }
  }

  // In addition also compute the directional derivative
  direc_deriv->calc_deriv( s.Gf().get_k(0)(), s.c().get_k(0)(), s.d().get_k(0)() );

  if( (int)olevel >= (int)PRINT_ALGORITHM_STEPS ) {
    out << "\nmu_k = " << s.mu().get_k(0) << "\n";
  }

  return true;
}