diff --git a/src/Optimization/CMakeLists.txt b/src/Optimization/CMakeLists.txt index 30b7bdc6..30e35d54 100644 --- a/src/Optimization/CMakeLists.txt +++ b/src/Optimization/CMakeLists.txt @@ -5,9 +5,10 @@ set(hiopOptimization_SRC hiopResidual.cpp hiopFilter.cpp hiopAlgFilterIPM.cpp - hiopKKTLinSys.cpp + hiopKKTLinSys.cpp + KktLinSysLowRank.cpp hiopKKTLinSysMDS.cpp - hiopHessianLowRank.cpp + HessianDiagPlusRowRank.cpp hiopDualsUpdater.cpp hiopNlpTransforms.cpp hiopPDPerturbation.cpp @@ -27,7 +28,7 @@ set(hiopOptimization_INTERFACE_HEADERS hiopDualsUpdater.hpp hiopFactAcceptor.hpp hiopFilter.hpp - hiopHessianLowRank.hpp + HessianDiagPlusRowRank.hpp hiopIterate.hpp hiopKKTLinSys.hpp hiopKKTLinSysDense.hpp diff --git a/src/Optimization/hiopHessianLowRank.cpp b/src/Optimization/HessianDiagPlusRowRank.cpp similarity index 51% rename from src/Optimization/hiopHessianLowRank.cpp rename to src/Optimization/HessianDiagPlusRowRank.cpp index cba17d07..f6d6f5b9 100644 --- a/src/Optimization/hiopHessianLowRank.cpp +++ b/src/Optimization/HessianDiagPlusRowRank.cpp @@ -1,6 +1,5 @@ // Copyright (c) 2017, Lawrence Livermore National Security, LLC. // Produced at the Lawrence Livermore National Laboratory (LLNL). -// Written by Cosmin G. Petra, petra1@llnl.gov. // LLNL-CODE-742473. All rights reserved. // // This file is part of HiOp. For details, see https://github.com/LLNL/hiop. HiOp @@ -46,7 +45,14 @@ // Lawrence Livermore National Security, LLC, and shall not be used for advertising or // product endorsement purposes. -#include "hiopHessianLowRank.hpp" +/** + * @file HessianDiagPlusRowRank.cpp + * + * @author Cosmin G. Petra , LLNL + * + */ + +#include "HessianDiagPlusRowRank.hpp" #include "LinAlgFactory.hpp" #include "hiopVectorPar.hpp" @@ -56,8 +62,6 @@ #include "mpi.h" #endif -//#include //!remove me - #include #include #include @@ -75,94 +79,110 @@ using namespace std; namespace hiop { - hiopHessianLowRank::hiopHessianLowRank(hiopNlpDenseConstraints* nlp_in, int max_mem_len) - : l_max(max_mem_len), l_curr(-1), sigma(1.), sigma0(1.), nlp(nlp_in), matrixChanged(false) +HessianDiagPlusRowRank::HessianDiagPlusRowRank(hiopNlpDenseConstraints* nlp_in, int max_mem_len) + : l_max_(max_mem_len), + l_curr_(-1), + sigma_(1.), + sigma0_(1.), + nlp_(nlp_in), + matrix_changed_(false) { - DhInv = nlp->alloc_primal_vec(); - St_ = nlp->alloc_multivector_primal(0, l_max); - Yt_ = St_->alloc_clone(); //faster than nlp->alloc_multivector_primal(...); + DhInv_ = nlp_->alloc_primal_vec(); + St_ = nlp_->alloc_multivector_primal(0, l_max_); + Yt_ = St_->alloc_clone(); //faster than nlp_->alloc_multivector_primal(...); //these are local L_ = LinearAlgebraFactory::create_matrix_dense("DEFAULT", 0, 0); D_ = LinearAlgebraFactory::create_vector("DEFAULT", 0); V_ = LinearAlgebraFactory::create_matrix_dense("DEFAULT", 0, 0); - //the previous iteration's objects are set to NULL - it_prev_ = new hiopIterate(nlp); - grad_f_prev_ = nlp->alloc_primal_vec(); - Jac_c_prev_ = nlp->alloc_Jac_c(); - Jac_d_prev_ = nlp->alloc_Jac_d(); + //the previous iteration + it_prev_ = new hiopIterate(nlp_); + grad_f_prev_ = nlp_->alloc_primal_vec(); + Jac_c_prev_ = nlp_->alloc_Jac_c(); + Jac_d_prev_ = nlp_->alloc_Jac_d(); //internal buffers for memory pool (none of them should be in n) #ifdef HIOP_USE_MPI - _buff_kxk = new double[nlp->m() * nlp->m()]; - _buff_2lxk = new double[nlp->m() * 2*l_max]; - _buff1_lxlx3 = new double[3*l_max*l_max]; - _buff2_lxlx3 = new double[3*l_max*l_max]; + buff_kxk_ = new double[nlp_->m() * nlp_->m()]; + buff_2lxk_ = new double[nlp_->m() * 2*l_max_]; + buff1_lxlx3_ = new double[3*l_max_*l_max_]; + buff2_lxlx3_ = new double[3*l_max_*l_max_]; #else //not needed in non-MPI mode - _buff_kxk = NULL; - _buff_2lxk = NULL; - _buff1_lxlx3 = _buff2_lxlx3 = NULL; + buff_kxk_ = nullptr; + buff_2lxk_ = nullptr; + buff1_lxlx3_ = nullptr; + buff2_lxlx3_ = nullptr; #endif //auxiliary objects/buffers - _S1=_Y1=NULL; - _lxl_mat1=_kxl_mat1=_kx2l_mat1=NULL; - _l_vec1 = _l_vec2 = _2l_vec1 = NULL; - _n_vec1 = DhInv->alloc_clone(); - _n_vec2 = DhInv->alloc_clone(); - - _V_work_vec=LinearAlgebraFactory::create_vector("DEFAULT", 0); - _V_ipiv_vec=NULL; _V_ipiv_size=-1; - + S1_ = nullptr; + Y1_ = nullptr; + lxl_mat1_ = nullptr; + kxl_mat1_ = nullptr; + kx2l_mat1_ = nullptr; + l_vec1_ = nullptr; + l_vec2_ = nullptr; + twol_vec1_ = nullptr; + n_vec1_ = DhInv_->alloc_clone(); + n_vec2_ = DhInv_->alloc_clone(); + + V_work_vec_ = LinearAlgebraFactory::create_vector("DEFAULT", 0); + V_ipiv_vec_ = nullptr; + V_ipiv_size_ = -1; - sigma0 = nlp->options->GetNumeric("sigma0"); - sigma=sigma0; + sigma0_ = nlp_->options->GetNumeric("sigma0"); + sigma_ = sigma0_; - string sigma_strategy = nlp->options->GetString("sigma_update_strategy"); + string sigma_strategy = nlp_->options->GetString("sigma_update_strategy"); transform(sigma_strategy.begin(), sigma_strategy.end(), sigma_strategy.begin(), ::tolower); - sigma_update_strategy = SIGMA_STRATEGY3; - if(sigma_strategy=="sty") - sigma_update_strategy=SIGMA_STRATEGY1; - else if(sigma_strategy=="sty_inv") - sigma_update_strategy=SIGMA_STRATEGY2; - else if(sigma_strategy=="snrm_ynrm") - sigma_update_strategy=SIGMA_STRATEGY3; - else if(sigma_strategy=="sty_srnm_ynrm") - sigma_update_strategy=SIGMA_STRATEGY4; - else if(sigma_strategy=="sigma0") - sigma_update_strategy=SIGMA_CONSTANT; - else assert(false && "sigma_update_strategy option not recognized"); - - sigma_safe_min=1e-8; - sigma_safe_max=1e+8; - nlp->log->printf(hovScalars, "Hessian Low Rank: initial sigma is %g\n", sigma); - nlp->log->printf(hovScalars, "Hessian Low Rank: sigma update strategy is %d [%s]\n", sigma_update_strategy, sigma_strategy.c_str()); - - _Dx = DhInv->alloc_clone(); + sigma_update_strategy_ = SIGMA_STRATEGY3; + if(sigma_strategy=="sty") { + sigma_update_strategy_=SIGMA_STRATEGY1; + } else if(sigma_strategy=="sty_inv") { + sigma_update_strategy_=SIGMA_STRATEGY2; + } else if(sigma_strategy=="snrm_ynrm") { + sigma_update_strategy_=SIGMA_STRATEGY3; + } else if(sigma_strategy=="sty_srnm_ynrm") { + sigma_update_strategy_=SIGMA_STRATEGY4; + } else if(sigma_strategy=="sigma0") { + sigma_update_strategy_=SIGMA_CONSTANT; + } else { + assert(false && "sigma_update_strategy option not recognized"); + } + + sigma_safe_min_ = 1e-8; + sigma_safe_max_ = 1e+8; + nlp_->log->printf(hovScalars, "Hessian Low Rank: initial sigma is %g\n", sigma_); + nlp_->log->printf(hovScalars, + "Hessian Low Rank: sigma update strategy is %d [%s]\n", + sigma_update_strategy_, + sigma_strategy.c_str()); + + Dx_ = DhInv_->alloc_clone(); #ifdef HIOP_DEEPCHECKS - _Vmat = V_->alloc_clone(); + Vmat_ = V_->alloc_clone(); #endif - yk = nlp->alloc_primal_vec(); - sk = nlp->alloc_primal_vec(); + yk = nlp_->alloc_primal_vec(); + sk = nlp_->alloc_primal_vec(); } -hiopHessianLowRank::~hiopHessianLowRank() +HessianDiagPlusRowRank::~HessianDiagPlusRowRank() { - if(DhInv) delete DhInv; - delete _Dx; + delete DhInv_; + delete Dx_; delete St_; delete Yt_; delete L_; delete D_; delete V_; - if(yk) delete yk; - if(sk) delete sk; + delete yk; + delete sk; #ifdef HIOP_DEEPCHECKS - delete _Vmat; + delete Vmat_; #endif @@ -171,24 +191,24 @@ hiopHessianLowRank::~hiopHessianLowRank() delete Jac_c_prev_; delete Jac_d_prev_; - if(_buff_kxk) delete[] _buff_kxk; - if(_buff_2lxk) delete[] _buff_2lxk; - if(_buff1_lxlx3) delete[] _buff1_lxlx3; - if(_buff2_lxlx3) delete[] _buff2_lxlx3; - - if(_S1) delete _S1; - if(_Y1) delete _Y1; - if(_lxl_mat1) delete _lxl_mat1; - if(_kxl_mat1) delete _kxl_mat1; - if(_kx2l_mat1) delete _kx2l_mat1; - - if(_l_vec1) delete _l_vec1; - if(_l_vec2) delete _l_vec2; - if(_n_vec1) delete _n_vec1; - if(_n_vec2) delete _n_vec2; - if(_2l_vec1) delete _2l_vec1; - if(_V_ipiv_vec) delete[] _V_ipiv_vec; - if(_V_work_vec) delete _V_work_vec; + delete[] buff_kxk_; + delete[] buff_2lxk_; + delete[] buff1_lxlx3_; + delete[] buff2_lxlx3_; + + delete S1_; + delete Y1_; + delete lxl_mat1_; + delete kxl_mat1_; + delete kx2l_mat1_; + + delete l_vec1_; + delete l_vec2_; + delete n_vec1_; + delete n_vec2_; + delete twol_vec1_; + delete[] V_ipiv_vec_; + delete V_work_vec_; for(auto* it: a) { delete it; @@ -199,18 +219,18 @@ hiopHessianLowRank::~hiopHessianLowRank() } } -void hiopHessianLowRank::alloc_for_limited_mem(const size_type& mem_length) +void HessianDiagPlusRowRank::alloc_for_limited_mem(const size_type& mem_length) { - //note: St_ and Yt_ always have l_curr rows - if(l_curr == mem_length) { - assert(D_->get_size() == l_curr); + //note: St_ and Yt_ always have l_curr_ rows + if(l_curr_ == mem_length) { + assert(D_->get_size() == l_curr_); return; } delete D_; delete L_; delete Yt_; delete St_; - St_ = nlp->alloc_multivector_primal(mem_length, l_max); + St_ = nlp_->alloc_multivector_primal(mem_length, l_max_); Yt_ = St_->alloc_clone(); //these are local @@ -218,64 +238,68 @@ void hiopHessianLowRank::alloc_for_limited_mem(const size_type& mem_length) D_ = LinearAlgebraFactory::create_vector("DEFAULT", mem_length); } -bool hiopHessianLowRank::updateLogBarrierDiagonal(const hiopVector& Dx) +bool HessianDiagPlusRowRank::update_logbar_diag(const hiopVector& Dx) { - DhInv->setToConstant(sigma); - DhInv->axpy(1.0,Dx); - _Dx->copyFrom(Dx); + DhInv_->setToConstant(sigma_); + DhInv_->axpy(1.0,Dx); + Dx_->copyFrom(Dx); #ifdef HIOP_DEEPCHECKS - assert(DhInv->allPositive()); + assert(DhInv_->allPositive()); #endif - DhInv->invert(); - nlp->log->write("hiopHessianLowRank: inverse diag DhInv:", *DhInv, hovMatrices); - matrixChanged=true; + DhInv_->invert(); + nlp_->log->write("HessianDiagPlusRowRank: inverse diag DhInv:", *DhInv_, hovMatrices); + matrix_changed_ = true; return true; } #ifdef HIOP_DEEPCHECKS -void hiopHessianLowRank::print(FILE* f, hiopOutVerbosity v, const char* msg) const +void HessianDiagPlusRowRank::print(FILE* f, hiopOutVerbosity v, const char* msg) const { fprintf(f, "%s\n", msg); #ifdef HIOP_DEEPCHECKS - nlp->log->write("Dx", *_Dx, v); + nlp_->log->write("Dx", *Dx_, v); #else fprintf(f, "Dx is not stored in this class, but it can be computed from Dx=DhInv^(1)-sigma"); #endif - nlp->log->printf(v, "sigma=%22.16f;\n", sigma); - nlp->log->write("DhInv", *DhInv, v); - nlp->log->write("S_trans", *St_, v); - nlp->log->write("Y_trans", *Yt_, v); + nlp_->log->printf(v, "sigma=%22.16f;\n", sigma_); + nlp_->log->write("DhInv", *DhInv_, v); + nlp_->log->write("S_trans", *St_, v); + nlp_->log->write("Y_trans", *Yt_, v); fprintf(f, " [[Internal representation]]\n"); #ifdef HIOP_DEEPCHECKS - nlp->log->write("V", *_Vmat, v); + nlp_->log->write("V", *Vmat_, v); #else - fprintf(f, "V matrix is available at this point (only its LAPACK factorization). Print it in updateInternalBFGSRepresentation() instead, before factorizeV()\n"); + fprintf(f, + "V matrix is available at this point (only its LAPACK factorization). Print it in " + "updateInternalBFGSRepresentation() instead, before factorizeV()\n"); #endif - nlp->log->write("L", *L_, v); - nlp->log->write("D", *D_, v); + nlp_->log->write("L", *L_, v); + nlp_->log->write("D", *D_, v); } #endif #include -bool hiopHessianLowRank::update(const hiopIterate& it_curr, const hiopVector& grad_f_curr_, - const hiopMatrix& Jac_c_curr_, const hiopMatrix& Jac_d_curr_) +bool HessianDiagPlusRowRank::update(const hiopIterate& it_curr, + const hiopVector& grad_f_curr, + const hiopMatrix& Jac_c_curr_in, + const hiopMatrix& Jac_d_curr_in) { - nlp->runStats.tmSolverInternal.start(); + nlp_->runStats.tmSolverInternal.start(); - const hiopMatrixDense& Jac_c_curr = dynamic_cast(Jac_c_curr_); - const hiopMatrixDense& Jac_d_curr = dynamic_cast(Jac_d_curr_); + const hiopMatrixDense& Jac_c_curr = dynamic_cast(Jac_c_curr_in); + const hiopMatrixDense& Jac_d_curr = dynamic_cast(Jac_d_curr_in); #ifdef HIOP_DEEPCHECKS - assert(it_curr.zl->matchesPattern(nlp->get_ixl())); - assert(it_curr.zu->matchesPattern(nlp->get_ixu())); - assert(it_curr.sxl->matchesPattern(nlp->get_ixl())); - assert(it_curr.sxu->matchesPattern(nlp->get_ixu())); + assert(it_curr.zl->matchesPattern(nlp_->get_ixl())); + assert(it_curr.zu->matchesPattern(nlp_->get_ixu())); + assert(it_curr.sxl->matchesPattern(nlp_->get_ixl())); + assert(it_curr.sxu->matchesPattern(nlp_->get_ixu())); #endif - //on first call l_curr=-1 - if(l_curr>=0) { - size_type n=grad_f_curr_.get_size(); + //on first call l_curr_=-1 + if(l_curr_>=0) { + size_type n = grad_f_curr.get_size(); //compute s_new = x_curr-x_prev hiopVector& s_new = new_n_vec1(n); s_new.copyFrom(*it_curr.x); @@ -286,10 +310,10 @@ bool hiopHessianLowRank::update(const hiopIterate& it_curr, const hiopVector& gr //compute y_new = \grad J(x_curr,\lambda_curr) - \grad J(x_prev, \lambda_curr) (yes, J(x_prev, \lambda_curr)) // = graf_f_curr-grad_f_prev + (Jac_c_curr-Jac_c_prev)yc_curr+ (Jac_d_curr-Jac_c_prev)yd_curr - zl_curr*s_new + zu_curr*s_new hiopVector& y_new = new_n_vec2(n); - y_new.copyFrom(grad_f_curr_); + y_new.copyFrom(grad_f_curr); y_new.axpy(-1., *grad_f_prev_); Jac_c_curr.transTimesVec (1.0, y_new, 1.0, *it_curr.yc); - //!opt if nlp->Jac_c_isLinear no need for the multiplications + //!opt if nlp_->Jac_c_isLinear no need for the multiplications Jac_c_prev_->transTimesVec(1.0, y_new,-1.0, *it_curr.yc); //!opt same here Jac_d_curr.transTimesVec (1.0, y_new, 1.0, *it_curr.yd); @@ -298,92 +322,97 @@ bool hiopHessianLowRank::update(const hiopIterate& it_curr, const hiopVector& gr double sTy = s_new.dotProductWith(y_new), s_nrm2=s_new.twonorm(), y_nrm2=y_new.twonorm(); #ifdef HIOP_DEEPCHECKS - nlp->log->printf(hovLinAlgScalarsVerb, "hiopHessianLowRank: s^T*y=%20.14e ||s||=%20.14e ||y||=%20.14e\n", sTy, s_nrm2, y_nrm2); - nlp->log->write("hiopHessianLowRank s_new",s_new, hovIteration); - nlp->log->write("hiopHessianLowRank y_new",y_new, hovIteration); + nlp_->log->printf(hovLinAlgScalarsVerb, + "HessianDiagPlusRowRank: s^T*y=%20.14e ||s||=%20.14e ||y||=%20.14e\n", + sTy, + s_nrm2, + y_nrm2); + nlp_->log->write("HessianDiagPlusRowRank s_new",s_new, hovIteration); + nlp_->log->write("HessianDiagPlusRowRank y_new",y_new, hovIteration); #endif if(sTy>s_nrm2*y_nrm2*sqrt(std::numeric_limits::epsilon())) { //sTy far away from zero - if(l_max>0) { + if(l_max_>0) { //compute the new row in L, update S and Y (either augment them or shift cols and add s_new and y_new) - hiopVector& YTs = new_l_vec1(l_curr); + hiopVector& YTs = new_l_vec1(l_curr_); Yt_->timesVec(0.0, YTs, 1.0, s_new); //update representation - if(l_currappendRow(s_new); Yt_->appendRow(y_new); - growL(l_curr, l_max, YTs); - growD(l_curr, l_max, sTy); - l_curr++; + growL(l_curr_, l_max_, YTs); + growD(l_curr_, l_max_, sTy); + l_curr_++; } else { //shift St_->shiftRows(-1); Yt_->shiftRows(-1); - St_->replaceRow(l_max-1, s_new); - Yt_->replaceRow(l_max-1, y_new); + St_->replaceRow(l_max_-1, s_new); + Yt_->replaceRow(l_max_-1, y_new); updateL(YTs,sTy); updateD(sTy); - l_curr=l_max; + l_curr_ = l_max_; } - } //end of l_max>0 + } //end of l_max_>0 #ifdef HIOP_DEEPCHECKS - nlp->log->printf(hovMatrices, "\nhiopHessianLowRank: these are L and D from the BFGS compact representation\n"); - nlp->log->write("L", *L_, hovMatrices); - nlp->log->write("D", *D_, hovMatrices); - nlp->log->printf(hovMatrices, "\n"); + nlp_->log->printf(hovMatrices, "\nHessianDiagPlusRowRank: these are L and D from the BFGS compact representation\n"); + nlp_->log->write("L", *L_, hovMatrices); + nlp_->log->write("D", *D_, hovMatrices); + nlp_->log->printf(hovMatrices, "\n"); #endif //update B0 (i.e., sigma) - switch (sigma_update_strategy ) { + switch (sigma_update_strategy_ ) { case SIGMA_STRATEGY1: - sigma=sTy/(s_nrm2*s_nrm2); + sigma_ = sTy/(s_nrm2*s_nrm2); break; case SIGMA_STRATEGY2: - sigma=y_nrm2*y_nrm2/sTy; + sigma_ = y_nrm2*y_nrm2/sTy; break; case SIGMA_STRATEGY3: - sigma=sqrt(s_nrm2*s_nrm2 / y_nrm2 / y_nrm2); + sigma_ = sqrt(s_nrm2*s_nrm2 / y_nrm2 / y_nrm2); break; case SIGMA_STRATEGY4: - sigma=0.5*(sTy/(s_nrm2*s_nrm2)+y_nrm2*y_nrm2/sTy); + sigma_ = 0.5*(sTy/(s_nrm2*s_nrm2)+y_nrm2*y_nrm2/sTy); break; case SIGMA_CONSTANT: - sigma=sigma0; + sigma_ = sigma0_; break; default: assert(false && "Option value for sigma_update_strategy was not recognized."); break; } // else of the switch //safe guard it - sigma=fmax(fmin(sigma_safe_max, sigma), sigma_safe_min); - nlp->log->printf(hovLinAlgScalars, "hiopHessianLowRank: sigma was updated to %22.16e\n", sigma); + sigma_ = fmax(fmin(sigma_safe_max_, sigma_), sigma_safe_min_); + nlp_->log->printf(hovLinAlgScalars, "HessianDiagPlusRowRank: sigma was updated to %22.16e\n", sigma_); } else { //sTy is too small or negative -> skip - nlp->log->printf(hovLinAlgScalars, "hiopHessianLowRank: s^T*y=%12.6e not positive enough... skipping the Hessian update\n", sTy); + nlp_->log->printf(hovLinAlgScalars, + "HessianDiagPlusRowRank: s^T*y=%12.6e not positive enough... skipping the Hessian update\n", + sTy); } } else {// norm of s_new is too small -> skip - nlp->log->printf(hovLinAlgScalars, "hiopHessianLowRank: ||s_new||=%12.6e too small... skipping the Hessian update\n", s_infnorm); + nlp_->log->printf(hovLinAlgScalars, + "HessianDiagPlusRowRank: ||s_new||=%12.6e too small... skipping the Hessian update\n", + s_infnorm); } - //save this stuff for next update it_prev_->copyFrom(it_curr); - grad_f_prev_->copyFrom(grad_f_curr_); + grad_f_prev_->copyFrom(grad_f_curr); Jac_c_prev_->copyFrom(Jac_c_curr); Jac_d_prev_->copyFrom(Jac_d_curr); - nlp->log->printf(hovLinAlgScalarsVerb, "hiopHessianLowRank: storing the iteration info as 'previous'\n", s_infnorm); - + nlp_->log->printf(hovLinAlgScalarsVerb, "HessianDiagPlusRowRank: storing the iteration info as 'previous'\n", s_infnorm); } else { //this is the first optimization iterate, just save the iterate and exit it_prev_->copyFrom(it_curr); - grad_f_prev_->copyFrom(grad_f_curr_); + grad_f_prev_->copyFrom(grad_f_curr); Jac_c_prev_->copyFrom(Jac_c_curr); Jac_d_prev_->copyFrom(Jac_d_curr); - nlp->log->printf(hovLinAlgScalarsVerb, "HessianLowRank on first update, just saving iteration\n"); + nlp_->log->printf(hovLinAlgScalarsVerb, "HessianLowRank on first update, just saving iteration\n"); - l_curr++; + l_curr_++; } - - nlp->runStats.tmSolverInternal.stop(); + nlp_->runStats.tmSolverInternal.stop(); return true; } @@ -397,7 +426,7 @@ bool hiopHessianLowRank::update(const hiopIterate& it_curr, const hiopVector& gr * In this function V is factorized and it will hold the factors at the end of the function * Note that L, D, S, and Y are from the BFGS secant representation and are updated/computed in 'update' */ -void hiopHessianLowRank::updateInternalBFGSRepresentation() +void HessianDiagPlusRowRank::updateInternalBFGSRepresentation() { size_type n=St_->n(); size_type l=St_->m(); @@ -418,10 +447,10 @@ void hiopHessianLowRank::updateInternalBFGSRepresentation() //-- block (2,2) hiopMatrixDense& DpYtDhInvY = new_lxl_mat1(l); - symmMatTimesDiagTimesMatTrans_local(0.0, DpYtDhInvY, 1.0,*Yt_,*DhInv); + sym_mat_times_diag_times_mattrans_local(0.0, DpYtDhInvY, 1.0,*Yt_,*DhInv_); #ifdef HIOP_USE_MPI const size_t buffsize=l*l*sizeof(double); - memcpy(_buff1_lxlx3, DpYtDhInvY.local_data(), buffsize); + memcpy(buff1_lxlx3_, DpYtDhInvY.local_data(), buffsize); #else DpYtDhInvY.addDiagonal(1., *D_); V_->copyBlockFromMatrix(l,l,DpYtDhInvY); @@ -430,10 +459,11 @@ void hiopHessianLowRank::updateInternalBFGSRepresentation() //-- block (1,2) hiopMatrixDense& StB0DhInvYmL = DpYtDhInvY; //just a rename hiopVector& B0DhInv = new_n_vec1(n); - B0DhInv.copyFrom(*DhInv); B0DhInv.scale(sigma); - matTimesDiagTimesMatTrans_local(StB0DhInvYmL, *St_, B0DhInv, *Yt_); + B0DhInv.copyFrom(*DhInv_); + B0DhInv.scale(sigma_); + mat_times_diag_times_mattrans_local(StB0DhInvYmL, *St_, B0DhInv, *Yt_); #ifdef HIOP_USE_MPI - memcpy(_buff1_lxlx3+l*l, StB0DhInvYmL.local_data(), buffsize); + memcpy(buff1_lxlx3_+l*l, StB0DhInvYmL.local_data(), buffsize); #else //substract L StB0DhInvYmL.addMatrix(-1.0, *L_); @@ -444,11 +474,11 @@ void hiopHessianLowRank::updateInternalBFGSRepresentation() //-- block (2,2) hiopVector& theDiag = B0DhInv; //just a rename, also reuses values theDiag.addConstant(-1.0); //at this point theDiag=DhInv*B0-I - theDiag.scale(sigma); + theDiag.scale(sigma_); hiopMatrixDense& StDS = DpYtDhInvY; //a rename - symmMatTimesDiagTimesMatTrans_local(0.0, StDS, 1.0, *St_, theDiag); + sym_mat_times_diag_times_mattrans_local(0.0, StDS, 1.0, *St_, theDiag); #ifdef HIOP_USE_MPI - memcpy(_buff1_lxlx3+2*l*l, DpYtDhInvY.local_data(), buffsize); + memcpy(buff1_lxlx3_+2*l*l, DpYtDhInvY.local_data(), buffsize); #else V_->copyBlockFromMatrix(0,0,StDS); #endif @@ -456,32 +486,33 @@ void hiopHessianLowRank::updateInternalBFGSRepresentation() #ifdef HIOP_USE_MPI int ierr; - ierr = MPI_Allreduce(_buff1_lxlx3, _buff2_lxlx3, 3*l*l, MPI_DOUBLE, MPI_SUM, nlp->get_comm()); assert(ierr==MPI_SUCCESS); + ierr = MPI_Allreduce(buff1_lxlx3_, buff2_lxlx3_, 3*l*l, MPI_DOUBLE, MPI_SUM, nlp_->get_comm()); + assert(ierr==MPI_SUCCESS); // - block (2,2) - DpYtDhInvY.copyFrom(_buff2_lxlx3); + DpYtDhInvY.copyFrom(buff2_lxlx3_); DpYtDhInvY.addDiagonal(1., *D_); - V_->copyBlockFromMatrix(l,l,DpYtDhInvY); + V_->copyBlockFromMatrix(l, l, DpYtDhInvY); // - block (1,2) - StB0DhInvYmL.copyFrom(_buff2_lxlx3+l*l); + StB0DhInvYmL.copyFrom(buff2_lxlx3_+l*l); StB0DhInvYmL.addMatrix(-1.0, *L_); - V_->copyBlockFromMatrix(0,l,StB0DhInvYmL); + V_->copyBlockFromMatrix(0, l, StB0DhInvYmL); // - block (1,1) - StDS.copyFrom(_buff2_lxlx3+2*l*l); - V_->copyBlockFromMatrix(0,0,StDS); + StDS.copyFrom(buff2_lxlx3_ + 2*l*l); + V_->copyBlockFromMatrix(0, 0, StDS); #endif #ifdef HIOP_DEEPCHECKS - delete _Vmat; - _Vmat = V_->new_copy(); - _Vmat->overwriteLowerTriangleWithUpper(); + delete Vmat_; + Vmat_ = V_->new_copy(); + Vmat_->overwriteLowerTriangleWithUpper(); #endif //finally, factorize V factorizeV(); - matrixChanged=false; + matrix_changed_ = false; } /* Solves this*x = res as x = this^{-1}*res @@ -492,44 +523,48 @@ void hiopHessianLowRank::updateInternalBFGSRepresentation() * M is is nxn, S,Y are nxl, V is upper triangular 2lx2l, and x is nx1 * Remember we store Yt=Y^T and St=S^T */ -void hiopHessianLowRank::solve(const hiopVector& rhsx, hiopVector& x) +void HessianDiagPlusRowRank::solve(const hiopVector& rhsx, hiopVector& x) { - if(matrixChanged) updateInternalBFGSRepresentation(); + if(matrix_changed_) { + updateInternalBFGSRepresentation(); + } size_type n=St_->n(), l=St_->m(); #ifdef HIOP_DEEPCHECKS assert(rhsx.get_size()==n); assert(x.get_size()==n); - assert(DhInv->get_size()==n); - assert(DhInv->isfinite_local() && "inf or nan entry detected"); + assert(DhInv_->get_size()==n); + assert(DhInv_->isfinite_local() && "inf or nan entry detected"); assert(rhsx.isfinite_local() && "inf or nan entry detected in rhs"); #endif //1. x = DhInv*res x.copyFrom(rhsx); - x.componentMult(*DhInv); + x.componentMult(*DhInv_); //2. stx= S^T*B0*DhInv*res and ytx=Y^T*DhInv*res - hiopVector&stx=new_l_vec1(l), &ytx=new_l_vec2(l); - stx.setToZero(); ytx.setToZero(); - Yt_->timesVec(0.0,ytx,1.0,x); + hiopVector& stx = new_l_vec1(l); + hiopVector& ytx = new_l_vec2(l); + stx.setToZero(); + ytx.setToZero(); + Yt_->timesVec(0.0, ytx, 1.0, x); hiopVector& B0DhInvx = new_n_vec1(n); B0DhInvx.copyFrom(x); //it contains DhInv*res - B0DhInvx.scale(sigma); //B0*(DhInv*res) + B0DhInvx.scale(sigma_); //B0*(DhInv*res) St_->timesVec(0.0, stx, 1.0, B0DhInvx); //3. solve with V hiopVector& spart=stx; hiopVector& ypart=ytx; - solveWithV(spart,ypart); + solve_with_V(spart,ypart); //4. multiply with DhInv*[B0*S Y], namely // result = DhInv*(B0*S*spart + Y*ypart) hiopVector& result = new_n_vec1(n); St_->transTimesVec(0.0, result, 1.0, spart); - result.scale(sigma); + result.scale(sigma_); Yt_->transTimesVec(1.0, result, 1.0, ypart); - result.componentMult(*DhInv); + result.componentMult(*DhInv_); //5. x = first term - second term = x_computed_in_1 - result x.axpy(-1.0,result); @@ -546,13 +581,14 @@ void hiopHessianLowRank::solve(const hiopVector& rhsx, hiopVector& x) * W is kxk, S,Y are nxl, DhInv,B0 are n, V is 2lx2l * X is kxn */ -void hiopHessianLowRank:: -symMatTimesInverseTimesMatTrans(double beta, - hiopMatrixDense& W, - double alpha, - const hiopMatrixDense& X) +void HessianDiagPlusRowRank::sym_mat_times_inverse_times_mattrans(double beta, + hiopMatrixDense& W, + double alpha, + const hiopMatrixDense& X) { - if(matrixChanged) updateInternalBFGSRepresentation(); + if(matrix_changed_) { + updateInternalBFGSRepresentation(); + } size_type n=St_->n(), l=St_->m(); size_type k=W.m(); @@ -560,26 +596,28 @@ symMatTimesInverseTimesMatTrans(double beta, assert(X.n()==n); #ifdef HIOP_DEEPCHECKS - nlp->log->write("symMatTimesInverseTimesMatTrans: X is: ", X, hovMatrices); + nlp_->log->write("sym_mat_times_inverse_times_mattrans: X is: ", X, hovMatrices); #endif //1. compute W=beta*W + alpha*X*DhInv*X' #ifdef HIOP_USE_MPI - if(0==nlp->get_rank()) - symmMatTimesDiagTimesMatTrans_local(beta,W,alpha,X,*DhInv); - else - symmMatTimesDiagTimesMatTrans_local(0.0, W,alpha,X,*DhInv); + if(0==nlp_->get_rank()) { + sym_mat_times_diag_times_mattrans_local(beta,W,alpha,X,*DhInv_); + } else { + sym_mat_times_diag_times_mattrans_local(0.0, W,alpha,X,*DhInv_); + } //W will be MPI_All_reduced later #else - symmMatTimesDiagTimesMatTrans_local(beta,W,alpha,X,*DhInv); + sym_mat_times_diag_times_mattrans_local(beta,W,alpha,X,*DhInv_); #endif //2. compute S1=X*DhInv*B0*S and Y1=X*DhInv*Y - auto& S1=new_S1(X,*St_); - auto& Y1=new_Y1(X,*Yt_); //both are kxl + auto& S1 = new_S1(X, *St_); + auto& Y1 = new_Y1(X, *Yt_); //both are kxl hiopVector& B0DhInv = new_n_vec1(n); - B0DhInv.copyFrom(*DhInv); B0DhInv.scale(sigma); - matTimesDiagTimesMatTrans_local(S1, X, B0DhInv, *St_); - matTimesDiagTimesMatTrans_local(Y1, X, *DhInv, *Yt_); + B0DhInv.copyFrom(*DhInv_); + B0DhInv.scale(sigma_); + mat_times_diag_times_mattrans_local(S1, X, B0DhInv, *St_); + mat_times_diag_times_mattrans_local(Y1, X, *DhInv_, *Yt_); //3. reduce W, S1, and Y1 (dimensions: kxk, kxl, kxl) hiopMatrixDense& S2Y2 = new_kx2l_mat1(k,l); //Initialy S2Y2 = [Y1 S1] @@ -587,23 +625,25 @@ symMatTimesInverseTimesMatTrans(double beta, S2Y2.copyBlockFromMatrix(0,l,Y1); #ifdef HIOP_USE_MPI int ierr; - ierr = MPI_Allreduce(S2Y2.local_data(), _buff_2lxk, 2*l*k, MPI_DOUBLE, MPI_SUM, nlp->get_comm()); assert(ierr==MPI_SUCCESS); - ierr = MPI_Allreduce(W.local_data(), _buff_kxk, k*k, MPI_DOUBLE, MPI_SUM, nlp->get_comm()); assert(ierr==MPI_SUCCESS); - S2Y2.copyFrom(_buff_2lxk); - W.copyFrom(_buff_kxk); + ierr = MPI_Allreduce(S2Y2.local_data(), buff_2lxk_, 2*l*k, MPI_DOUBLE, MPI_SUM, nlp_->get_comm()); + assert(ierr==MPI_SUCCESS); + ierr = MPI_Allreduce(W.local_data(), buff_kxk_, k*k, MPI_DOUBLE, MPI_SUM, nlp_->get_comm()); + assert(ierr==MPI_SUCCESS); + S2Y2.copyFrom(buff_2lxk_); + W.copyFrom(buff_kxk_); //also copy S1 and Y1 S1.copyFromMatrixBlock(S2Y2, 0,0); Y1.copyFromMatrixBlock(S2Y2, 0,l); #endif #ifdef HIOP_DEEPCHECKS - nlp->log->write("symMatTimesInverseTimesMatTrans: W first term is: ", W, hovMatrices); + nlp_->log->write("sym_mat_times_inverse_times_mattrans: W first term is: ", W, hovMatrices); #endif //4. [S2] = V \ [S1^T] // [Y2] [Y1^T] //S2Y2 is exactly [S1^T] when Fortran Lapack looks at it // [Y1^T] hiopMatrixDense& RHS_fortran = S2Y2; - solveWithV(RHS_fortran); + solve_with_V(RHS_fortran); //5. W = W-alpha*[S1 Y1]*[S2^T] // [Y2^T] @@ -617,20 +657,15 @@ symMatTimesInverseTimesMatTrans(double beta, Y2.copyFromMatrixBlock(S2Y2, 0, l); Y1.timesMatTrans_local(1.0, W, alpha, Y2); - //nlp->log->write("symMatTimesInverseTimesMatTrans: Y1 is : ", Y1, hovMatrices); - //nlp->log->write("symMatTimesInverseTimesMatTrans: Y2 is : ", Y2, hovMatrices); - //nlp->log->write("symMatTimesInverseTimesMatTrans: W is : ", W, hovMatrices); - - //we're done here - + //nlp_->log->write("sym_mat_times_inverse_times_mattrans: Y1 is : ", Y1, hovMatrices); + //nlp_->log->write("sym_mat_times_inverse_times_mattrans: Y2 is : ", Y2, hovMatrices); + //nlp_->log->write("sym_mat_times_inverse_times_mattrans: W is : ", W, hovMatrices); #ifdef HIOP_DEEPCHECKS - nlp->log->write("symMatTimesInverseTimesMatTrans: final matrix is : ", W, hovMatrices); + nlp_->log->write("sym_mat_times_inverse_times_mattrans: final matrix is : ", W, hovMatrices); #endif - } - -void hiopHessianLowRank::factorizeV() +void HessianDiagPlusRowRank::factorizeV() { int N = V_->n(); int lda = N; @@ -640,41 +675,53 @@ void hiopHessianLowRank::factorizeV() } #ifdef HIOP_DEEPCHECKS - nlp->log->write("factorizeV: V is ", *V_, hovMatrices); + nlp_->log->write("factorizeV: V is ", *V_, hovMatrices); #endif char uplo='L'; //V is upper in C++ so it's lower in fortran - if(_V_ipiv_vec==NULL) _V_ipiv_vec=new int[N]; - else if(_V_ipiv_size!=N) { delete[] _V_ipiv_vec; _V_ipiv_vec=new int[N]; _V_ipiv_size=N; } + if(V_ipiv_vec_==nullptr) { + V_ipiv_vec_ = new int[N]; + } + else { + if(V_ipiv_size_!=N) { + delete[] V_ipiv_vec_; + V_ipiv_vec_ = new int[N]; + V_ipiv_size_ = N; + } + } int lwork=-1;//inquire sizes double Vwork_tmp; - DSYTRF(&uplo, &N, V_->local_data(), &lda, _V_ipiv_vec, &Vwork_tmp, &lwork, &info); + DSYTRF(&uplo, &N, V_->local_data(), &lda, V_ipiv_vec_, &Vwork_tmp, &lwork, &info); assert(info==0); lwork=(int)Vwork_tmp; - if(lwork != _V_work_vec->get_size()) { - if(_V_work_vec!=NULL) { - delete _V_work_vec; + if(lwork != V_work_vec_->get_size()) { + if(V_work_vec_!=nullptr) { + delete V_work_vec_; } - _V_work_vec = LinearAlgebraFactory::create_vector("DEFAULT", lwork); - } else assert(_V_work_vec); + V_work_vec_ = LinearAlgebraFactory::create_vector("DEFAULT", lwork); + } else assert(V_work_vec_); - DSYTRF(&uplo, &N, V_->local_data(), &lda, _V_ipiv_vec, _V_work_vec->local_data(), &lwork, &info); + DSYTRF(&uplo, &N, V_->local_data(), &lda, V_ipiv_vec_, V_work_vec_->local_data(), &lwork, &info); - if(info<0) - nlp->log->printf(hovError, "hiopHessianLowRank::factorizeV error: %d argument to dsytrf has an illegal value\n", -info); - else if(info>0) - nlp->log->printf(hovError, "hiopHessianLowRank::factorizeV error: %d entry in the factorization's diagonal is exactly zero. Division by zero will occur if it a solve is attempted.\n", info); + if(info<0) { + nlp_->log->printf(hovError, "HessianDiagPlusRowRank::factorizeV error: %d arg to dsytrf has an illegal value\n", -info); + } else if(info>0) { + nlp_->log->printf(hovError, + "HessianDiagPlusRowRank::factorizeV error: %d entry in the factorization's diagonal is exactly zero. " + "Division by zero will occur if a solve is attempted.\n", + info); + } assert(info==0); #ifdef HIOP_DEEPCHECKS - nlp->log->write("factorizeV: factors of V: ", *V_, hovMatrices); + nlp_->log->write("factorizeV: factors of V: ", *V_, hovMatrices); #endif } -void hiopHessianLowRank::solveWithV(hiopVector& rhs_s, hiopVector& rhs_y) +void HessianDiagPlusRowRank::solve_with_V(hiopVector& rhs_s, hiopVector& rhs_y) { int N = V_->n(); if(N==0) { @@ -684,8 +731,8 @@ void hiopHessianLowRank::solveWithV(hiopVector& rhs_s, hiopVector& rhs_y) int l = rhs_s.get_size(); #ifdef HIOP_DEEPCHECKS - nlp->log->write("hiopHessianLowRank::solveWithV: RHS IN 's' part: ", rhs_s, hovMatrices); - nlp->log->write("hiopHessianLowRank::solveWithV: RHS IN 'y' part: ", rhs_y, hovMatrices); + nlp_->log->write("HessianDiagPlusRowRank::solve_with_V: RHS IN 's' part: ", rhs_s, hovMatrices); + nlp_->log->write("HessianDiagPlusRowRank::solve_with_V: RHS IN 'y' part: ", rhs_y, hovMatrices); hiopVector* rhs_saved= LinearAlgebraFactory::create_vector("DEFAULT", rhs_s.get_size()+rhs_y.get_size()); rhs_saved->copyFromStarting(0, rhs_s); rhs_saved->copyFromStarting(l, rhs_y); @@ -700,9 +747,11 @@ void hiopHessianLowRank::solveWithV(hiopVector& rhs_s, hiopVector& rhs_y) rhs.copyFromStarting(0, rhs_s); rhs.copyFromStarting(l, rhs_y); - DSYTRS(&uplo, &N, &one, V_->local_data(), &lda, _V_ipiv_vec, rhs.local_data(), &N, &info); + DSYTRS(&uplo, &N, &one, V_->local_data(), &lda, V_ipiv_vec_, rhs.local_data(), &N, &info); - if(info<0) nlp->log->printf(hovError, "hiopHessianLowRank::solveWithV error: %d argument to dsytrf has an illegal value\n", -info); + if(info<0) { + nlp_->log->printf(hovError, "HessianDiagPlusRowRank::solve_with_V error: %d arg to dsytrf has an illegal value\n", -info); + } assert(info==0); //copy back the solution @@ -710,23 +759,24 @@ void hiopHessianLowRank::solveWithV(hiopVector& rhs_s, hiopVector& rhs_y) rhs.copyToStarting(l,rhs_y); #ifdef HIOP_DEEPCHECKS - nlp->log->write("solveWithV: SOL OUT 's' part: ", rhs_s, hovMatrices); - nlp->log->write("solveWithV: SOL OUT 'y' part: ", rhs_y, hovMatrices); + nlp_->log->write("solve_with_V: SOL OUT 's' part: ", rhs_s, hovMatrices); + nlp_->log->write("solve_with_V: SOL OUT 'y' part: ", rhs_y, hovMatrices); //residual calculation double nrmrhs=rhs_saved->infnorm(); - _Vmat->timesVec(1.0, *rhs_saved, -1.0, rhs); + Vmat_->timesVec(1.0, *rhs_saved, -1.0, rhs); double nrmres=rhs_saved->infnorm(); - //nlp->log->printf(hovLinAlgScalars, "hiopHessianLowRank::solveWithV 1rhs: rel resid norm=%g\n", nrmres/(1+nrmrhs)); - nlp->log->printf(hovScalars, "hiopHessianLowRank::solveWithV 1rhs: rel resid norm=%g\n", nrmres/(1+nrmrhs)); - if(nrmres>1e-8) - nlp->log->printf(hovWarning, "hiopHessianLowRank::solveWithV large residual=%g\n", nrmres); + //nlp_->log->printf(hovLinAlgScalars, "HessianDiagPlusRowRank::solve_with_V 1rhs: rel resid norm=%g\n", nrmres/(1+nrmrhs)); + nlp_->log->printf(hovScalars, "HessianDiagPlusRowRank::solve_with_V 1rhs: rel resid norm=%g\n", nrmres/(1+nrmrhs)); + if(nrmres>1e-8) { + nlp_->log->printf(hovWarning, "HessianDiagPlusRowRank::solve_with_V large residual=%g\n", nrmres); + } delete rhs_saved; #endif } -void hiopHessianLowRank::solveWithV(hiopMatrixDense& rhs) +void HessianDiagPlusRowRank::solve_with_V(hiopMatrixDense& rhs) { int N = V_->n(); if(0==N) { @@ -734,7 +784,7 @@ void hiopHessianLowRank::solveWithV(hiopMatrixDense& rhs) } #ifdef HIOP_DEEPCHECKS - nlp->log->write("solveWithV: RHS IN: ", rhs, hovMatrices); + nlp_->log->write("solve_with_V: RHS IN: ", rhs, hovMatrices); hiopMatrixDense* rhs_saved = rhs.new_copy(); #endif @@ -745,12 +795,14 @@ void hiopHessianLowRank::solveWithV(hiopMatrixDense& rhs) #ifdef HIOP_DEEPCHECKS assert(N==rhs.n()); #endif - DSYTRS(&uplo, &N, &nrhs, V_->local_data(), &lda, _V_ipiv_vec, rhs.local_data(), &ldb, &info); + DSYTRS(&uplo, &N, &nrhs, V_->local_data(), &lda, V_ipiv_vec_, rhs.local_data(), &ldb, &info); - if(info<0) nlp->log->printf(hovError, "hiopHessianLowRank::solveWithV error: %d argument to dsytrf has an illegal value\n", -info); + if(info<0) { + nlp_->log->printf(hovError, "HessianDiagPlusRowRank::solve_with_V error: %d arg to dsytrf has an illegal value\n", -info); + } assert(info==0); #ifdef HIOP_DEEPCHECKS - nlp->log->write("solveWithV: SOL OUT: ", rhs, hovMatrices); + nlp_->log->write("solve_with_V: SOL OUT: ", rhs, hovMatrices); hiopMatrixDense& sol = rhs; //matrix of solutions /// TODO: get rid of these uses of specific hiopVector implementation @@ -762,13 +814,19 @@ void hiopHessianLowRank::solveWithV(hiopMatrixDense& rhs) rhs_saved->getRow(k, *r); sol.getRow(k,*x); double nrmrhs = r->infnorm();//nrmrhs=.0; - _Vmat->timesVec(1.0, *r, -1.0, *x); + Vmat_->timesVec(1.0, *r, -1.0, *x); double nrmres = r->infnorm(); - if(nrmres>1e-8) - nlp->log->printf(hovWarning, "hiopHessianLowRank::solveWithV mult-rhs: rhs number %d has large resid norm=%g\n", k, nrmres); - if(nrmres/(nrmrhs+1)>resnorm) resnorm=nrmres/(nrmrhs+1); + if(nrmres>1e-8) { + nlp_->log->printf(hovWarning, + "HessianDiagPlusRowRank::solve_with_V mult-rhs: rhs number %d has large resid norm=%g\n", + k, + nrmres); + } + if(nrmres/(nrmrhs+1)>resnorm) { + resnorm=nrmres/(nrmrhs+1); + } } - nlp->log->printf(hovLinAlgScalars, "hiopHessianLowRank::solveWithV mult-rhs: rel resid norm=%g\n", resnorm); + nlp_->log->printf(hovLinAlgScalars, "HessianDiagPlusRowRank::solve_with_V mult-rhs: rel resid norm=%g\n", resnorm); delete x; delete r; delete rhs_saved; @@ -776,7 +834,7 @@ void hiopHessianLowRank::solveWithV(hiopMatrixDense& rhs) } -void hiopHessianLowRank::growL(const int& lmem_curr, const int& lmem_max, const hiopVector& YTs) +void HessianDiagPlusRowRank::growL(const int& lmem_curr, const int& lmem_max, const hiopVector& YTs) { int l = L_->m(); #ifdef HIOP_DEEPCHECKS @@ -791,30 +849,34 @@ void hiopHessianLowRank::growL(const int& lmem_curr, const int& lmem_max, const //copy from L to newL newL->copyBlockFromMatrix(0,0, *L_); - double* newL_mat=newL->local_data(); //doing the rest here - const double* YTs_vec=YTs.local_data_const(); + double* newL_mat = newL->local_data(); //doing the rest here + const double* YTs_vec = YTs.local_data_const(); //for(int j=0; jget_size(); assert(l==lmem_curr); assert(lmem_max>=l); - hiopVector* Dnew=LinearAlgebraFactory::create_vector("DEFAULT", l+1); - double* Dnew_vec=Dnew->local_data(); + hiopVector* Dnew = LinearAlgebraFactory::create_vector("DEFAULT", l+1); + double* Dnew_vec = Dnew->local_data(); memcpy(Dnew_vec, D_->local_data_const(), l*sizeof(double)); - Dnew_vec[l]=sTy; + Dnew_vec[l] = sTy; delete D_; D_ = Dnew; @@ -823,14 +885,14 @@ void hiopHessianLowRank::growD(const int& lmem_curr, const int& lmem_max, const /* L_{ij} = s_{i-1}^T y_{j-1}, if i>j, otherwise zero. Here i,j = 0,1,...,l_curr-1 * L_new = lift and shift L to the left; replace last row with [Yts;0] */ -void hiopHessianLowRank::updateL(const hiopVector& YTs, const double& sTy) +void HessianDiagPlusRowRank::updateL(const hiopVector& YTs, const double& sTy) { int l=YTs.get_size(); assert(l==L_->m()); assert(l==L_->n()); #ifdef HIOP_DEEPCHECKS - assert(l_curr==l); - assert(l_curr==l_max); + assert(l_curr_==l); + assert(l_curr_==l_max_); #endif const int lm1=l-1; double* L_mat=L_->local_data(); @@ -850,172 +912,191 @@ void hiopHessianLowRank::updateL(const hiopVector& YTs, const double& sTy) //first entry in YTs corresponds to y_to_be_discarded_since_it_is_the_oldest'* s_new and is discarded for(int j=0; jget_size(); double* D_vec = D_->local_data(); - for(int i=0; iget_size()==l) return *_l_vec1; - - if(_l_vec1!=NULL) { - delete _l_vec1; + if(l_vec1_!=nullptr && l_vec1_->get_size()==l) { + return *l_vec1_; } - _l_vec1= LinearAlgebraFactory::create_vector("DEFAULT", l); - return *_l_vec1; + if(l_vec1_!=nullptr) { + delete l_vec1_; + } + l_vec1_= LinearAlgebraFactory::create_vector("DEFAULT", l); + return *l_vec1_; } -hiopVector& hiopHessianLowRank::new_l_vec2(int l) + +hiopVector& HessianDiagPlusRowRank::new_l_vec2(int l) { - if(_l_vec2!=NULL && _l_vec2->get_size()==l) return *_l_vec2; - - if(_l_vec2!=NULL) { - delete _l_vec2; + if(l_vec2_!=nullptr && l_vec2_->get_size()==l) { + return *l_vec2_; + } + if(l_vec2_!=nullptr) { + delete l_vec2_; } - _l_vec2= LinearAlgebraFactory::create_vector("DEFAULT", l); - return *_l_vec2; + l_vec2_= LinearAlgebraFactory::create_vector("DEFAULT", l); + return *l_vec2_; } -hiopMatrixDense& hiopHessianLowRank::new_lxl_mat1(int l) +hiopMatrixDense& HessianDiagPlusRowRank::new_lxl_mat1(int l) { - if(_lxl_mat1!=NULL) { - if( l==_lxl_mat1->m() ) { - return *_lxl_mat1; + if(lxl_mat1_!=nullptr) { + if(l==lxl_mat1_->m()) { + return *lxl_mat1_; } else { - delete _lxl_mat1; - _lxl_mat1=NULL; + delete lxl_mat1_; + lxl_mat1_=nullptr; } } - _lxl_mat1 = LinearAlgebraFactory::create_matrix_dense("DEFAULT", l, l); - return *_lxl_mat1; + lxl_mat1_ = LinearAlgebraFactory::create_matrix_dense("DEFAULT", l, l); + return *lxl_mat1_; } -hiopMatrixDense& hiopHessianLowRank::new_kx2l_mat1(int k, int l) + +hiopMatrixDense& HessianDiagPlusRowRank::new_kx2l_mat1(int k, int l) { - int twol=2*l; - if(NULL!=_kx2l_mat1) { - assert(_kx2l_mat1->m()==k); - if( twol==_kx2l_mat1->n() ) { - return *_kx2l_mat1; + const int twol=2*l; + if(nullptr!=kx2l_mat1_) { + assert(kx2l_mat1_->m()==k); + if(twol==kx2l_mat1_->n()) { + return *kx2l_mat1_; } else { - delete _kx2l_mat1; - _kx2l_mat1=NULL; + delete kx2l_mat1_; + kx2l_mat1_=nullptr; } } - _kx2l_mat1 = LinearAlgebraFactory::create_matrix_dense("DEFAULT", k, twol); - - return *_kx2l_mat1; + kx2l_mat1_ = LinearAlgebraFactory::create_matrix_dense("DEFAULT", k, twol); + return *kx2l_mat1_; } -hiopMatrixDense& hiopHessianLowRank::new_kxl_mat1(int k, int l) + +hiopMatrixDense& HessianDiagPlusRowRank::new_kxl_mat1(int k, int l) { - if(_kxl_mat1!=NULL) { - assert(_kxl_mat1->m()==k); - if( l==_kxl_mat1->n() ) { - return *_kxl_mat1; + if(kxl_mat1_!=nullptr) { + assert(kxl_mat1_->m()==k); + if( l==kxl_mat1_->n() ) { + return *kxl_mat1_; } else { - delete _kxl_mat1; - _kxl_mat1=NULL; + delete kxl_mat1_; + kxl_mat1_=nullptr; } } - _kxl_mat1 = LinearAlgebraFactory::create_matrix_dense("DEFAULT", k, l); - return *_kxl_mat1; + kxl_mat1_ = LinearAlgebraFactory::create_matrix_dense("DEFAULT", k, l); + return *kxl_mat1_; } -hiopMatrixDense& hiopHessianLowRank::new_S1(const hiopMatrixDense& X, const hiopMatrixDense& St) + +hiopMatrixDense& HessianDiagPlusRowRank::new_S1(const hiopMatrixDense& X, const hiopMatrixDense& St) { //S1 is X*some_diag*S (kxl). Here St=S^T is lxn and X is kxn (l BFGS memory size, k number of constraints) - size_type k=X.m(), l=St.m(); + size_type k = X.m(); + size_type l = St.m(); #ifdef HIOP_DEEPCHECKS assert(St.n()==X.n()); - if(_S1!=NULL) - assert(_S1->m()==k); + if(S1_!=nullptr) { + assert(S1_->m()==k); + } #endif - if(NULL!=_S1 && _S1->n()!=l) { delete _S1; _S1=NULL; } - - if(NULL==_S1) _S1=LinearAlgebraFactory::create_matrix_dense("DEFAULT", k, l); - - return *_S1; + if(nullptr!=S1_ && S1_->n()!=l) { + delete S1_; + S1_=nullptr; + } + if(nullptr==S1_) { + S1_=LinearAlgebraFactory::create_matrix_dense("DEFAULT", k, l); + } + return *S1_; } -hiopMatrixDense& hiopHessianLowRank::new_Y1(const hiopMatrixDense& X, const hiopMatrixDense& Yt) +hiopMatrixDense& HessianDiagPlusRowRank::new_Y1(const hiopMatrixDense& X, const hiopMatrixDense& Yt) { //Y1 is X*somediag*Y (kxl). Here Yt=Y^T is lxn, X is kxn - size_type k=X.m(), l=Yt.m(); + size_type k = X.m(); + size_type l = Yt.m(); #ifdef HIOP_DEEPCHECKS assert(X.n()==Yt.n()); - if(_Y1!=NULL) assert(_Y1->m()==k); + if(Y1_!=nullptr) { + assert(Y1_->m()==k); + } #endif - - if(NULL!=_Y1 && _Y1->n()!=l) { delete _Y1; _Y1=NULL; } - - if(NULL==_Y1) _Y1=LinearAlgebraFactory::create_matrix_dense("DEFAULT", k, l); - return *_Y1; + if(nullptr!=Y1_ && Y1_->n()!=l) { + delete Y1_; + Y1_ = nullptr; + } + if(nullptr==Y1_) { + Y1_ = LinearAlgebraFactory::create_matrix_dense("DEFAULT", k, l); + } + return *Y1_; } #ifdef HIOP_DEEPCHECKS -void hiopHessianLowRank::timesVec_noLogBarrierTerm(double beta, hiopVector& y, double alpha, const hiopVector&x) +void HessianDiagPlusRowRank::times_vec_no_logbar_term(double beta, hiopVector& y, double alpha, const hiopVector&x) { - this->timesVecCmn(beta, y, alpha, x, false); + this->times_vec_common(beta, y, alpha, x, false); } #endif //HIOP_DEEPCHECKS -void hiopHessianLowRank:: -timesVecCmn(double beta, hiopVector& y, double alpha, const hiopVector& x, bool addLogTerm) const +void HessianDiagPlusRowRank:: +times_vec_common(double beta, hiopVector& y, double alpha, const hiopVector& x, bool addLogTerm) const { size_type n=St_->n(); - assert(l_curr==St_->m()); + assert(l_curr_==St_->m()); assert(y.get_size()==n); assert(St_->get_local_size_n() == Yt_->get_local_size_n()); //we have B+=B-B*s*B*s'/(s'*B*s)+yy'/(y'*s) - //B0 is sigma*I. There is an additional diagonal log-barrier term _Dx + //B0 is sigma*I. There is an additional diagonal log-barrier term Dx_ bool print=false; if(print) { - nlp->log->printf(hovMatrices, "---hiopHessianLowRank::timesVec \n"); - nlp->log->write("S=", *St_, hovMatrices); - nlp->log->write("Y=", *Yt_, hovMatrices); - nlp->log->write("DhInv=", *DhInv, hovMatrices); - nlp->log->printf(hovMatrices, "sigma=%22.16e; addLogTerm=%d;\n", sigma, addLogTerm); - if(addLogTerm) - nlp->log->write("Dx=", *_Dx, hovMatrices); - nlp->log->printf(hovMatrices, "y=beta*y + alpha*this*x : beta=%g alpha=%g\n", beta, alpha); - nlp->log->write("x_in=", x, hovMatrices); - nlp->log->write("y_in=", y, hovMatrices); + nlp_->log->printf(hovMatrices, "---HessianDiagPlusRowRank::times_vec \n"); + nlp_->log->write("S=", *St_, hovMatrices); + nlp_->log->write("Y=", *Yt_, hovMatrices); + nlp_->log->write("DhInv=", *DhInv_, hovMatrices); + nlp_->log->printf(hovMatrices, "sigma=%22.16e; addLogTerm=%d;\n", sigma_, addLogTerm); + if(addLogTerm) { + nlp_->log->write("Dx=", *Dx_, hovMatrices); + } + nlp_->log->printf(hovMatrices, "y=beta*y + alpha*this*x : beta=%g alpha=%g\n", beta, alpha); + nlp_->log->write("x_in=", x, hovMatrices); + nlp_->log->write("y_in=", y, hovMatrices); } //allocate and compute a_k and b_k //! make sure the pointers within these std::vectors are deallocated - a.resize(l_curr, nullptr); - b.resize(l_curr, nullptr); + a.resize(l_curr_, nullptr); + b.resize(l_curr_, nullptr); int n_local = Yt_->get_local_size_n(); - for(int k=0; kcopyFrom(Yt_->local_data() + k*n_local); sk->copyFrom(St_->local_data() + k*n_local); double skTyk=yk->dotProductWith(*sk); if(skTyk < std::numeric_limits::epsilon()) { - nlp->log->printf(hovLinAlgScalars, "hiopHessianLowRank: ||s_k^T*y_k||=%12.6e too small..." - " set it to machine precision = %12.6e \n", skTyk, std::numeric_limits::epsilon()); + nlp_->log->printf(hovLinAlgScalars, + "HessianDiagPlusRowRank: ||s_k^T*y_k||=%12.6e too small and was set it to mach eps = %12.6e \n", + skTyk, + std::numeric_limits::epsilon()); skTyk = std::numeric_limits::epsilon(); } if(a[k] == nullptr && b[k] == nullptr) { - b[k] = nlp->alloc_primal_vec(); - a[k] = nlp->alloc_primal_vec(); + b[k] = nlp_->alloc_primal_vec(); + a[k] = nlp_->alloc_primal_vec(); } b[k]->copyFrom(*yk); @@ -1023,7 +1104,7 @@ timesVecCmn(double beta, hiopVector& y, double alpha, const hiopVector& x, bool //compute ak by an inner loop a[k]->copyFrom(*sk); - a[k]->scale(sigma); + a[k]->scale(sigma_); for(int i=0; idotProductWith(*sk); @@ -1040,11 +1121,11 @@ timesVecCmn(double beta, hiopVector& y, double alpha, const hiopVector& x, bool //y = beta*y+alpha*(B0+Dx)*x + alpha* sum { bk'x bk - ak'x ak : k=0,1,...,l_curr-1} y.scale(beta); if(addLogTerm) - y.axzpy(alpha,x,*_Dx); + y.axzpy(alpha, x, *Dx_); - y.axpy(alpha*sigma, x); + y.axpy(alpha*sigma_, x); - for(int k=0; kdotProductWith(x); double akTx = a[k]->dotProductWith(x); @@ -1053,19 +1134,19 @@ timesVecCmn(double beta, hiopVector& y, double alpha, const hiopVector& x, bool } if(print) { - nlp->log->write("y_out=", y, hovMatrices); + nlp_->log->write("y_out=", y, hovMatrices); } } -void hiopHessianLowRank::timesVec(double beta, hiopVector& y, double alpha, const hiopVector&x) +void HessianDiagPlusRowRank::times_vec(double beta, hiopVector& y, double alpha, const hiopVector&x) { - this->timesVecCmn(beta, y, alpha, x); + this->times_vec_common(beta, y, alpha, x); } -void hiopHessianLowRank::timesVec(double beta, hiopVector& y, double alpha, const hiopVector&x) const +void HessianDiagPlusRowRank::timesVec(double beta, hiopVector& y, double alpha, const hiopVector&x) const { - this->timesVecCmn(beta, y, alpha, x); + this->times_vec_common(beta, y, alpha, x); } /************************************************************************** @@ -1076,10 +1157,11 @@ void hiopHessianLowRank::timesVec(double beta, hiopVector& y, double alpha, cons * W is kxk local, X is kxn distributed and Diag is n, distributed * The ops are perform locally. The reduce is done separately/externally to decrease comm */ -void hiopHessianLowRank:: -symmMatTimesDiagTimesMatTrans_local(double beta, hiopMatrixDense& W, - double alpha, const hiopMatrixDense& X, - const hiopVector& d) +void HessianDiagPlusRowRank::sym_mat_times_diag_times_mattrans_local(double beta, + hiopMatrixDense& W, + double alpha, + const hiopMatrixDense& X, + const hiopVector& d) { size_type k=W.m(); size_type n_local=X.get_local_size_n(); @@ -1116,8 +1198,10 @@ symmMatTimesDiagTimesMatTrans_local(double beta, hiopMatrixDense& W, } /* W=S*D*X^T, where S is lxn, D is diag nxn, and X is kxn */ -void hiopHessianLowRank:: -matTimesDiagTimesMatTrans_local(hiopMatrixDense& W, const hiopMatrixDense& S, const hiopVector& d, const hiopMatrixDense& X) +void HessianDiagPlusRowRank::mat_times_diag_times_mattrans_local(hiopMatrixDense& W, + const hiopMatrixDense& S, + const hiopVector& d, + const hiopMatrixDense& X) { #ifdef HIOP_DEEPCHECKS assert(S.n()==d.get_size()); diff --git a/src/Optimization/hiopHessianLowRank.hpp b/src/Optimization/HessianDiagPlusRowRank.hpp similarity index 64% rename from src/Optimization/hiopHessianLowRank.hpp rename to src/Optimization/HessianDiagPlusRowRank.hpp index 05457c1e..89d85e53 100644 --- a/src/Optimization/hiopHessianLowRank.hpp +++ b/src/Optimization/HessianDiagPlusRowRank.hpp @@ -46,6 +46,13 @@ // Lawrence Livermore National Security, LLC, and shall not be used for advertising or // product endorsement purposes. +/** + * @file HessianDiagPlusRowRank.hpp + * + * @author Cosmin G. Petra , LLNL + * + */ + #ifndef HIOP_HESSIANLOWRANK #define HIOP_HESSIANLOWRANK @@ -57,17 +64,18 @@ namespace hiop { -/* Class for storing and solving with the low-rank Hessian +/** + * Encapsultes storage and solves with the Hessian being identity plus low-rank term. * - * Stores the Hessian wrt x as Hk=Dk+Bk, where + * Stores the Hessian (w.r.t. x) approximation as Hk=Dk+Bk, where * - Dk is the log barrier diagonal - * - Bk=B0 - M*N^{-1}*M^T is the secant approximation for the Hessian of the Lagrangian - * in the compact representation of Byrd, Nocedal, and Schnabel (1994) + * - Bk = B0 - M*N^{-1}*M^T is the secant approximation for the Hessian of the Lagrangian + * in the limited-memory compact representation of Byrd, Nocedal, and Schnabel (1994) * Reference: Byrd, Nocedal, and Schnabel, "Representations of quasi-Newton matrices and * and there use in limited memory methods", Math. Programming 63 (1994), p. 129-156. * * M=[B0*Sk Yk] is nx2l, and N is 2lx2l, where n=dim(x) and l is the length of the memory of secant - * approximation. This class is for when n>>k (l=O(10)). + * approximation. This class is for when n>>k and l=O(10). * * This class provides functionality to KKT linear system class for updating the secant approximation * and solving with Hk=Dk+Bk. @@ -88,73 +96,88 @@ namespace hiop * Parallel computations: Dk, B0 are distributed vectors, M is distributed * column-wise, and N is local (stored on all processors). */ -class hiopHessianLowRank : public hiopMatrix +class HessianDiagPlusRowRank : public hiopMatrix { public: - hiopHessianLowRank(hiopNlpDenseConstraints* nlp_in, int max_memory_length); - virtual ~hiopHessianLowRank(); + HessianDiagPlusRowRank(hiopNlpDenseConstraints* nlp_in, int max_memory_length); + virtual ~HessianDiagPlusRowRank(); - /* return false if the update destroys hereditary positive definitness and the BFGS update is not taken*/ - virtual bool update(const hiopIterate& x_curr, const hiopVector& grad_f_curr, - const hiopMatrix& Jac_c_curr, const hiopMatrix& Jac_d_curr); + /// Updates Hessian if hereditary positive definitness is maintained and returns true, otherwise false. + virtual bool update(const hiopIterate& x_curr, + const hiopVector& grad_f_curr, + const hiopMatrix& Jac_c_curr, + const hiopMatrix& Jac_d_curr); /* updates the logBar diagonal term from the representation */ - virtual bool updateLogBarrierDiagonal(const hiopVector& Dx); + virtual bool update_logbar_diag(const hiopVector& Dx); /* solves this*x=res */ virtual void solve(const hiopVector& rhs, hiopVector& x); + /* W = beta*W + alpha*X*inverse(this)*X^T (a more efficient version of solve) * This is performed as W = beta*W + alpha*X*(this\X^T) */ - virtual void symMatTimesInverseTimesMatTrans(double beta, hiopMatrixDense& W_, - double alpha, const hiopMatrixDense& X); + virtual void sym_mat_times_inverse_times_mattrans(double beta, hiopMatrixDense& W, double alpha, const hiopMatrixDense& X); #ifdef HIOP_DEEPCHECKS /* same as above but without the Dx term in H */ - virtual void timesVec_noLogBarrierTerm(double beta, hiopVector& y, double alpha, const hiopVector&x); + virtual void times_vec_no_logbar_term(double beta, hiopVector& y, double alpha, const hiopVector&x); virtual void print(FILE* f, hiopOutVerbosity v, const char* msg) const; #endif - /* computes the product of the Hessian with a vector: y=beta*y+alpha*H*x. + /* Computes the product of the Hessian with a vector: y=beta*y+alpha*H*x. * The function is supposed to use the underlying ***recursive*** definition of the * quasi-Newton Hessian and is used for checking/testing/error calculation. */ - virtual void timesVec(double beta, hiopVector& y, double alpha, const hiopVector&x); + virtual void times_vec(double beta, hiopVector& y, double alpha, const hiopVector&x); /* code shared by the above two methods*/ - virtual void timesVecCmn(double beta, hiopVector& y, double alpha, const hiopVector&x, bool addLogBarTerm = false) const; + virtual void times_vec_common(double beta, hiopVector& y, double alpha, const hiopVector&x, bool add_logbar = false) const; protected: friend class hiopAlgFilterIPMQuasiNewton; - int l_max; //max memory size - int l_curr; //number of pairs currently stored - double sigma; //initial scaling factor of identity - double sigma0; //default scaling factor of identity - int sigma_update_strategy; - double sigma_safe_min, sigma_safe_max; //min and max safety thresholds for sigma - hiopNlpDenseConstraints* nlp; + int l_max_; //max memory size + int l_curr_; //number of pairs currently stored + double sigma_; //initial scaling factor of identity + double sigma0_; //default scaling factor of identity + + //Integer for the sigma update strategy + int sigma_update_strategy_; + //Min safety thresholds for sigma + double sigma_safe_min_; + //Max safety thresholds for sigma + double sigma_safe_max_; + //Pointer to the NLP formulation + hiopNlpDenseConstraints* nlp_; + mutable std::vector a; mutable std::vector b; hiopVector* yk; hiopVector* sk; private: - hiopVector* DhInv; //(B0+Dk)^{-1} - // needed in timesVec (for residual checking in solveCompressed. - // can be recomputed from DhInv decided to store it instead to avoid round-off errors - hiopVector* _Dx; - bool matrixChanged; - //these are matrices from the compact representation; they are updated at each iteration. - // more exactly Bk=B0-[B0*St' Yt']*[St*B0*St' L]*[St*B0] - // [ L' -D] [Yt ] - //transpose of S and T are store to easily access columns + // Vector for (B0+Dk)^{-1} + hiopVector* DhInv_; + // Dx_ is needed in times_vec (for residual checking in solveCompressed). Can be recomputed from DhInv, but I decided to + //store it instead to avoid round-off errors + hiopVector* Dx_; + + bool matrix_changed_; + + //These are matrices from the compact representation; they are updated at each iteration. + //More exactly Bk=B0-[B0*St' Yt']*[St*B0*St' L]*[St*B0] + // [ L' -D] [Yt ] + //Transpose of S and T are store to easily access columns hiopMatrixDense* St_; - hiopMatrixDense* Yt_; - hiopMatrixDense* L_; //lower triangular from the compact representation - hiopVector* D_; //diag - //these are matrices from the representation of the inverse + hiopMatrixDense* Yt_; + + /// Lower triangular matrix from the compact representation + hiopMatrixDense* L_; + /// Diagonal matrix from the compact representation + hiopVector* D_; + // Matrix V from the representation of the inverse hiopMatrixDense* V_; #ifdef HIOP_DEEPCHECKS - //copy of the matrix - needed to check the residual - hiopMatrixDense* _Vmat; + //copy of the V matrix - needed to check the residual + hiopMatrixDense* Vmat_; #endif void growL(const int& lmem_curr, const int& lmem_max, const hiopVector& YTs); void growD(const int& l_curr, const int& l_max, const double& sTy); @@ -170,43 +193,76 @@ class hiopHessianLowRank : public hiopMatrix void updateInternalBFGSRepresentation(); //internals buffers, mostly for MPIAll_reduce - double* _buff_kxk; // size = num_constraints^2 - double* _buff_2lxk; // size = 2 x q-Newton mem size x num_constraints - double *_buff1_lxlx3, *_buff2_lxlx3; - //auxiliary objects - hiopMatrixDense *_S1, *_Y1, *_lxl_mat1, *_kx2l_mat1, *_kxl_mat1; //preallocated matrices - //holds X*D*S + double* buff_kxk_; // size = num_constraints^2 + double* buff_2lxk_; // size = 2 x q-Newton mem size x num_constraints + double* buff1_lxlx3_; + double* buff2_lxlx3_; + + // auxiliary objects preallocated and used in internally in various computation blocks + + /// See new_S1 + hiopMatrixDense* S1_; + /// See new_Y1 + hiopMatrixDense* Y1_; + + hiopMatrixDense* lxl_mat1_; + hiopMatrixDense* kx2l_mat1_; + hiopMatrixDense* kxl_mat1_; + + /** + * (Re)Allocates S1_ of size kxl to store is X*D*S, where D is a diagonal matrix. S comes in + * as St=S^T (lxn) and X comes in as kxn, where l is the BFGS memory size and k number of + * constraints. S1_ is allocated only if not already allocated or realocated only if it does + * not have the right dimesions to store X*D*S. + */ hiopMatrixDense& new_S1(const hiopMatrixDense& X, const hiopMatrixDense& St); - //holds X*D*Y + + /** + * (Re)Allocates Y1_ of size kxl to store is X*D*Y, where D is a diagonal matrix. Y comes in + * as Yt=Y^T (lxn) and X comes in as kxn, where l is the BFGS memory size and k number of + * constraints. Y1_ is allocated only if not already allocated or reallocated only if it does + * not have the right dimesions to store X*D*Y. + */ hiopMatrixDense& new_Y1(const hiopMatrixDense& X, const hiopMatrixDense& Yt); + hiopMatrixDense& new_lxl_mat1 (int l); hiopMatrixDense& new_kxl_mat1 (int k, int l); hiopMatrixDense& new_kx2l_mat1(int k, int l); - hiopVector *_l_vec1, *_l_vec2, *_n_vec1, *_n_vec2, *_2l_vec1; + hiopVector* l_vec1_; + hiopVector* l_vec2_; + hiopVector* n_vec1_; + hiopVector* n_vec2_; + hiopVector* twol_vec1_; hiopVector& new_l_vec1(int l); hiopVector& new_l_vec2(int l); inline hiopVector& new_n_vec1(size_type n) { #ifdef HIOP_DEEPCHECKS - assert(_n_vec1!=NULL); - assert(_n_vec1->get_size()==n); + assert(n_vec1_!=nullptr); + assert(n_vec1_->get_size()==n); #endif - return *_n_vec1; + return *n_vec1_; } inline hiopVector& new_n_vec2(size_type n) { #ifdef HIOP_DEEPCHECKS - assert(_n_vec2!=NULL); - assert(_n_vec2->get_size()==n); + assert(n_vec2_!=nullptr); + assert(n_vec2_->get_size()==n); #endif - return *_n_vec2; + return *n_vec2_; } - inline hiopVector& new_2l_vec1(int l) { - if(_2l_vec1!=NULL && _2l_vec1->get_size()==2*l) return *_2l_vec1; - if(_2l_vec1!=NULL) delete _2l_vec1; - _2l_vec1=LinearAlgebraFactory::create_vector(nlp->options->GetString("mem_space"), 2*l); - return *_2l_vec1; + inline hiopVector& new_2l_vec1(int l) + { + if(twol_vec1_!=nullptr && twol_vec1_->get_size()==2*l) { + return *twol_vec1_; + } + if(twol_vec1_!=nullptr) + { + delete twol_vec1_; + } + twol_vec1_=LinearAlgebraFactory::create_vector(nlp_->options->GetString("mem_space"), 2*l); + return *twol_vec1_; } private: //utilities @@ -215,34 +271,40 @@ class hiopHessianLowRank : public hiopMatrix void alloc_for_limited_mem(const size_type& mem_length); /* symmetric multiplication W = beta*W + alpha*X*Diag*X^T */ - static void symmMatTimesDiagTimesMatTrans_local(double beta, hiopMatrixDense& W_, - double alpha, const hiopMatrixDense& X_, - const hiopVector& d); + static void sym_mat_times_diag_times_mattrans_local(double beta, + hiopMatrixDense& W_, + double alpha, + const hiopMatrixDense& X_, + const hiopVector& d); /* W=S*Diag*X^T */ - static void matTimesDiagTimesMatTrans_local(hiopMatrixDense& W, const hiopMatrixDense& S, - const hiopVector& d, const hiopMatrixDense& X); + static void mat_times_diag_times_mattrans_local(hiopMatrixDense& W, + const hiopMatrixDense& S, + const hiopVector& d, + const hiopMatrixDense& X); /* members and utilities related to V matrix: factorization and solve */ - hiopVector *_V_work_vec; - int _V_ipiv_size; int* _V_ipiv_vec; + hiopVector* V_work_vec_; + int V_ipiv_size_; + int* V_ipiv_vec_; + void factorizeV(); - void solveWithV(hiopVector& rhs_s, hiopVector& rhs_y); - void solveWithV(hiopMatrixDense& rhs); + void solve_with_V(hiopVector& rhs_s, hiopVector& rhs_y); + void solve_with_V(hiopMatrixDense& rhs); private: - hiopHessianLowRank() {}; - hiopHessianLowRank(const hiopHessianLowRank&) {}; - hiopHessianLowRank& operator=(const hiopHessianLowRank&) {return *this;}; + HessianDiagPlusRowRank() {}; + HessianDiagPlusRowRank(const HessianDiagPlusRowRank&) {}; + HessianDiagPlusRowRank& operator=(const HessianDiagPlusRowRank&) {return *this;}; /* methods that need to be implemented as the class inherits from hiopMatrix*/ public: virtual hiopMatrix* alloc_clone() const { assert(false && "not provided because it is not needed"); - return NULL; + return nullptr; } virtual hiopMatrix* new_copy() const { assert(false && "not provided because it is not needed"); - return NULL; + return nullptr; } virtual void setToZero() @@ -257,8 +319,7 @@ class hiopHessianLowRank : public hiopMatrix void timesVec(double beta, hiopVector& y, double alpha, const hiopVector&x) const; /** y = beta * y + alpha * this^T * x */ - virtual void transTimesVec(double beta, hiopVector& y, - double alpha, const hiopVector& x ) const + virtual void transTimesVec(double beta, hiopVector& y, double alpha, const hiopVector& x ) const { assert(false && "not provided because it is not needed"); } @@ -293,8 +354,11 @@ class hiopHessianLowRank : public hiopMatrix /* add to the diagonal of 'this' (destination) starting at 'start_on_dest_diag' elements of * 'd_' (source) starting at index 'start_on_src_vec'. The number of elements added is 'num_elems' * when num_elems>=0, or the remaining elems on 'd_' starting at 'start_on_src_vec'. */ - virtual void addSubDiagonal(int start_on_dest_diag, const double& alpha, - const hiopVector& d_, int start_on_src_vec, int num_elems=-1) + virtual void addSubDiagonal(int start_on_dest_diag, + const double& alpha, + const hiopVector& d_, + int start_on_src_vec, + int num_elems=-1) { assert(false && "not needed / implemented"); } @@ -302,7 +366,6 @@ class hiopHessianLowRank : public hiopMatrix { assert(false && "not needed / implemented"); } - /* this += alpha*X */ virtual void addMatrix(double alpah, const hiopMatrix& X) @@ -318,8 +381,7 @@ class hiopHessianLowRank : public hiopMatrix { assert(false && "not needed; should not be used"); } - void addUpperTriangleToSymDenseMatrixUpperTriangle(int diag_start, - double alpha, hiopMatrixDense& W) const + void addUpperTriangleToSymDenseMatrixUpperTriangle(int diag_start, double alpha, hiopMatrixDense& W) const { assert(false && "not needed; should not be used"); } @@ -358,15 +420,23 @@ class hiopHessianLowRank : public hiopMatrix * given by the value of 'maxRows' will be printed. If this value is negative, all * elements will be printed. */ - virtual void print(FILE* f=NULL, const char* msg=NULL, int maxRows=-1, int maxCols=-1, int rank=-1) const + virtual void print(FILE* f=nullptr, const char* msg=nullptr, int maxRows=-1, int maxCols=-1, int rank=-1) const { assert(false && "not provided because it is not needed"); } /* number of rows */ - virtual size_type m() const { assert(false && "not provided because it is not needed"); return 0; } + virtual size_type m() const + { + assert(false && "method is not provided because it is not needed"); + return 0; + } /* number of columns */ - virtual size_type n() const { assert(false && "not provided because it is not needed"); return 0; } + virtual size_type n() const + { + assert(false && "method is not provided because it is not needed"); + return 0; + } #ifdef HIOP_DEEPCHECKS /* check symmetry */ virtual bool assertSymmetry(double tol=1e-16) const { return true; } diff --git a/src/Optimization/KktLinSysLowRank.cpp b/src/Optimization/KktLinSysLowRank.cpp new file mode 100644 index 00000000..11178a12 --- /dev/null +++ b/src/Optimization/KktLinSysLowRank.cpp @@ -0,0 +1,507 @@ +// Copyright (c) 2017, Lawrence Livermore National Security, LLC. +// Produced at the Lawrence Livermore National Laboratory (LLNL). +// LLNL-CODE-742473. All rights reserved. +// +// This file is part of HiOp. For details, see https://github.com/LLNL/hiop. HiOp +// is released under the BSD 3-clause license (https://opensource.org/licenses/BSD-3-Clause). +// Please also read "Additional BSD Notice" below. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// i. Redistributions of source code must retain the above copyright notice, this list +// of conditions and the disclaimer below. +// ii. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the disclaimer (as noted below) in the documentation and/or +// other materials provided with the distribution. +// iii. Neither the name of the LLNS/LLNL nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written +// permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +// SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Additional BSD Notice +// 1. This notice is required to be provided under our contract with the U.S. Department +// of Energy (DOE). This work was produced at Lawrence Livermore National Laboratory under +// Contract No. DE-AC52-07NA27344 with the DOE. +// 2. Neither the United States Government nor Lawrence Livermore National Security, LLC +// nor any of their employees, makes any warranty, express or implied, or assumes any +// liability or responsibility for the accuracy, completeness, or usefulness of any +// information, apparatus, product, or process disclosed, or represents that its use would +// not infringe privately-owned rights. +// 3. Also, reference herein to any specific commercial products, process, or services by +// trade name, trademark, manufacturer or otherwise does not necessarily constitute or +// imply its endorsement, recommendation, or favoring by the United States Government or +// Lawrence Livermore National Security, LLC. The views and opinions of authors expressed +// herein do not necessarily state or reflect those of the United States Government or +// Lawrence Livermore National Security, LLC, and shall not be used for advertising or +// product endorsement purposes. + +/** + * @file KktLinSysLowRank.cpp + * + * @author Cosmin G. Petra , LLNL + * + */ + +#include "KktLinSysLowRank.hpp" + +namespace hiop +{ + +KktLinSysLowRank::KktLinSysLowRank(hiopNlpFormulation* nlp) + : hiopKKTLinSysCompressedXYcYd(nlp) +{ + auto* nlpd = dynamic_cast(nlp_); + + kxn_mat_ = nlpd->alloc_multivector_primal(nlpd->m()); + assert("DEFAULT" == toupper(nlpd->options->GetString("mem_space"))); + N_ = LinearAlgebraFactory::create_matrix_dense(nlpd->options->GetString("mem_space"), + nlpd->m(), + nlpd->m()); +#ifdef HIOP_DEEPCHECKS + Nmat_ = N_->alloc_clone(); +#endif + k_vec1_ = nlpd->alloc_dual_vec(); +} + +KktLinSysLowRank::~KktLinSysLowRank() +{ + delete N_; +#ifdef HIOP_DEEPCHECKS + delete Nmat_; +#endif + delete kxn_mat_; + delete k_vec1_; +} + +bool KktLinSysLowRank::update(const hiopIterate* iter, + const hiopVector* grad_f, + const hiopMatrixDense* Jac_c, + const hiopMatrixDense* Jac_d, + HessianDiagPlusRowRank* hess_low_rank) +{ + nlp_->runStats.tmSolverInternal.start(); + + iter_ = iter; + grad_f_ = dynamic_cast(grad_f); + Jac_c_ = Jac_c; Jac_d_ = Jac_d; + Hess_ = hess_low_rank; + + //compute the diagonals + //Dx=(Sxl)^{-1}Zl + (Sxu)^{-1}Zu + Dx_->setToZero(); + Dx_->axdzpy_w_pattern(1.0, *iter_->zl, *iter_->sxl, nlp_->get_ixl()); + Dx_->axdzpy_w_pattern(1.0, *iter_->zu, *iter_->sxu, nlp_->get_ixu()); + nlp_->log->write("Dx in KKT", *Dx_, hovMatrices); + + hess_low_rank->update_logbar_diag(*Dx_); + + //Dd=(Sdl)^{-1}Vu + (Sdu)^{-1}Vu + Dd_inv_->setToZero(); + Dd_inv_->axdzpy_w_pattern(1.0, *iter_->vl, *iter_->sdl, nlp_->get_idl()); + Dd_inv_->axdzpy_w_pattern(1.0, *iter_->vu, *iter_->sdu, nlp_->get_idu()); +#ifdef HIOP_DEEPCHECKS + assert(true==Dd_inv_->allPositive()); +#endif + Dd_->copyFrom(*Dd_inv_); + Dd_inv_->invert(); + + nlp_->runStats.tmSolverInternal.stop(); + + nlp_->log->write("Dd_inv in KKT", *Dd_inv_, hovMatrices); + return true; +} + + +/* Solves the system corresponding to directions for x, yc, and yd, namely + * [ H_BFGS + Dx Jc^T Jd^T ] [ dx] [ rx ] + * [ Jc 0 0 ] [dyc] = [ ryc ] + * [ Jd 0 -Dd^{-1}] [dyd] [ ryd ] + * + * This is done by forming and solving + * [ Jc*(H+Dx)^{-1}*Jc^T Jc*(H+Dx)^{-1}*Jd^T ] [dyc] = [ Jc(H+Dx)^{-1} rx - ryc ] + * [ Jd*(H+Dx)^{-1}*Jc^T Jd*(H+Dx)^{-1}*Jd^T + Dd^{-1}] [dyd] [ Jd(H+dx)^{-1} rx - ryd ] + * and then solving for dx from + * dx = - (H+Dx)^{-1}*(Jc^T*dyc+Jd^T*dyd - rx) + * + * Note that ops H+Dx are provided by HessianDiagPlusRowRank + */ +bool KktLinSysLowRank::solveCompressed(hiopVector& rx, + hiopVector& ryc, + hiopVector& ryd, + hiopVector& dx, + hiopVector& dyc, + hiopVector& dyd) +{ +#ifdef HIOP_DEEPCHECKS + //some outputing + nlp_->log->write("KKT Low rank: solve compressed RHS", hovIteration); + nlp_->log->write(" rx: ", rx, hovIteration); + nlp_->log->write(" ryc: ", ryc, hovIteration); + nlp_->log->write(" ryd: ", ryd, hovIteration); + nlp_->log->write(" Jc: ", *Jac_c_, hovMatrices); + nlp_->log->write(" Jd: ", *Jac_d_, hovMatrices); + nlp_->log->write(" Dd_inv: ", *Dd_inv_, hovMatrices); + assert(Dd_inv_->isfinite_local() && "Something bad happened: nan or inf value"); +#endif + + hiopMatrixDense& J = *kxn_mat_; + const hiopMatrixDense* Jac_c_de = dynamic_cast(Jac_c_); assert(Jac_c_de); + const hiopMatrixDense* Jac_d_de = dynamic_cast(Jac_d_); assert(Jac_d_de); + J.copyRowsFrom(*Jac_c_de, nlp_->m_eq(), 0); //!opt + J.copyRowsFrom(*Jac_d_de, nlp_->m_ineq(), nlp_->m_eq());//!opt + + auto* hess_low_rank = dynamic_cast(Hess_); + + //N = J*(Hess\J') + //Hess->symmetricTimesMat(0.0, *N, 1.0, J); + hess_low_rank->sym_mat_times_inverse_times_mattrans(0.0, *N_, 1.0, J); + + //subdiag of N += 1., Dd_inv + N_->addSubDiagonal(1., nlp_->m_eq(), *Dd_inv_); +#ifdef HIOP_DEEPCHECKS + assert(J.isfinite()); + nlp_->log->write("solveCompressed: N is", *N_, hovMatrices); + nlp_->log->write("solveCompressed: rx is", rx, hovMatrices); + nlp_->log->printf(hovLinAlgScalars, "inf norm of Dd_inv is %g\n", Dd_inv_->infnorm()); + N_->assertSymmetry(1e-10); +#endif + + //compute the rhs of the lin sys involving N + // 1. first compute (H+Dx)^{-1} rx_tilde and store it temporarily in dx + hess_low_rank->solve(rx, dx); +#ifdef HIOP_DEEPCHECKS + assert(rx.isfinite_local() && "Something bad happened: nan or inf value"); + assert(dx.isfinite_local() && "Something bad happened: nan or inf value"); +#endif + + // 2 . then rhs = [ Jc(H+Dx)^{-1}*rx - ryc ] + // [ Jd(H+dx)^{-1}*rx - ryd ] + hiopVector& rhs=*k_vec1_; + rhs.copyFromStarting(0, ryc); + rhs.copyFromStarting(nlp_->m_eq(), ryd); + J.timesVec(-1.0, rhs, 1.0, dx); + +#ifdef HIOP_DEEPCHECKS + nlp_->log->write("solveCompressed: dx sol is", dx, hovMatrices); + nlp_->log->write("solveCompressed: rhs for N is", rhs, hovMatrices); + Nmat_->copyFrom(*N_); + hiopVector* r=rhs.new_copy(); //save the rhs to check the norm of the residual +#endif + + // + //solve N * dyc_dyd = rhs + // + int ierr = solveWithRefin(*N_,rhs); + //int ierr = solve(*N,rhs); + + hiopVector& dyc_dyd= rhs; + dyc_dyd.copyToStarting(0, dyc); + dyc_dyd.copyToStarting(nlp_->m_eq(), dyd); + + //now solve for dx = - (H+Dx)^{-1}*(Jc^T*dyc+Jd^T*dyd - rx) + //first rx = -(Jc^T*dyc+Jd^T*dyd - rx) + J.transTimesVec(1.0, rx, -1.0, dyc_dyd); + //then dx = (H+Dx)^{-1} rx + hess_low_rank->solve(rx, dx); + +#ifdef HIOP_DEEPCHECKS + //some outputing + nlp_->log->write("KKT Low rank: solve compressed SOL", hovIteration); + nlp_->log->write(" dx: ", dx, hovIteration); + nlp_->log->write(" dyc: ", dyc, hovIteration); + nlp_->log->write(" dyd: ", dyd, hovIteration); + delete r; +#endif + + return ierr==0; +} + +int KktLinSysLowRank::solveWithRefin(hiopMatrixDense& M, hiopVector& rhs) +{ + // 1. Solve dposvx (solve + equilibrating + iterative refinement + forward and backward error estimates) + // 2. Check the residual norm + // 3. If residual norm is not small enough, then perform iterative refinement. This is because dposvx + // does not always provide a small enough residual since it stops (possibly without refinement) based on + // the forward and backward estimates + + int N=M.n(); + if(N<=0) return 0; + + hiopMatrixDense* Aref = M.new_copy(); + hiopVector* rhsref = rhs.new_copy(); + + char FACT='E'; + char UPLO='L'; + + int NRHS=1; + double* A=M.local_data(); + int LDA=N; + double* AF=new double[N*N]; + int LDAF=N; + char EQUED='N'; //it is an output if FACT='E' + double* S = new double[N]; + double* B = rhs.local_data(); + int LDB=N; + double* X = new double[N]; + int LDX = N; + double RCOND, FERR, BERR; + double* WORK = new double[3*N]; + int* IWORK = new int[N]; + int INFO; + + // + // 1. solve + // + DPOSVX(&FACT, &UPLO, &N, &NRHS, A, &LDA, AF, &LDAF, &EQUED, S, B, &LDB, X, &LDX, &RCOND, &FERR, &BERR, WORK, IWORK, &INFO); + //printf("INFO ===== %d RCOND=%g FERR=%g BERR=%g EQUED=%c\n", INFO, RCOND, FERR, BERR, EQUED); + // + // 2. check residual + // + hiopVector* x = rhs.alloc_clone(); + hiopVector* dx = rhs.alloc_clone(); + hiopVector* resid = rhs.alloc_clone(); + int nIterRefin=0;double nrmResid; + int info; + const int MAX_ITER_REFIN=3; + while(true) { + x->copyFrom(X); + resid->copyFrom(*rhsref); + Aref->timesVec(1.0, *resid, -1.0, *x); + + nlp_->log->write("resid", *resid, hovLinAlgScalars); + + nrmResid= resid->infnorm(); + nlp_->log->printf(hovScalars, "KktLinSysLowRank::solveWithRefin iterrefin=%d residual norm=%g\n", nIterRefin, nrmResid); + + if(nrmResid<1e-8) break; + + if(nIterRefin>=MAX_ITER_REFIN) { + nlp_->log->write("N", *Aref, hovMatrices); + nlp_->log->write("sol", *x, hovMatrices); + nlp_->log->write("rhs", *rhsref, hovMatrices); + + nlp_->log->printf(hovWarning, + "KktLinSysLowRank::solveWithRefin reduced residual to ONLY (inf-norm) %g after %d iterative refinements\n", + nrmResid, + nIterRefin); + break; + //assert(false && "too many refinements"); + } + if(0) { //iter refin based on symmetric indefinite factorization+solve + + + int _V_ipiv_vec[1000]; + double _V_work_vec[1000]; + int lwork=1000; + M.copyFrom(*Aref); + DSYTRF(&UPLO, &N, M.local_data(), &LDA, _V_ipiv_vec, _V_work_vec, &lwork, &info); + assert(info==0); + DSYTRS(&UPLO, &N, &NRHS, M.local_data(), &LDA, _V_ipiv_vec, resid->local_data(), &LDB, &info); + assert(info==0); + } else { + //iter refin based on symmetric positive definite factorization+solve + M.copyFrom(*Aref); + DPOTRF(&UPLO, &N, M.local_data(), &LDA, &info); + if(info>0) { + nlp_->log->printf(hovError, + "KktLinSysLowRank::factorizeMat: dpotrf (Chol fact) detected %d minor being indefinite.\n", + info); + } else { + if(info<0) { + nlp_->log->printf(hovError, "KktLinSysLowRank::factorizeMat: dpotrf returned error %d\n", info); + } + } + + DPOTRS(&UPLO,&N, &NRHS, M.local_data(), &LDA, resid->local_data(), &LDA, &info); + if(info<0) { + nlp_->log->printf(hovError, "KktLinSysLowRank::solveWithFactors: dpotrs returned error %d\n", info); + } + } + + dx->copyFrom(*resid); + x->axpy(1., *dx); + + nIterRefin++; + } + rhs.copyFrom(*x); + delete[] AF; + delete[] S; + delete[] X; + delete[] WORK; + delete[] IWORK; + delete Aref; + delete rhsref; + delete x; + delete dx; + delete resid; + + return 0; +} + +int KktLinSysLowRank::solve(hiopMatrixDense& M, hiopVector& rhs) +{ + char FACT='E'; + char UPLO='L'; + int N=M.n(); + int NRHS=1; + double* A=M.local_data(); + int LDA=N; + double* AF=new double[N*N]; + int LDAF=N; + char EQUED='N'; //it is an output if FACT='E' + double* S = new double[N]; + double* B = rhs.local_data(); + int LDB=N; + double* X = new double[N]; + int LDX = N; + double RCOND, FERR, BERR; + double* WORK = new double[3*N]; + int* IWORK = new int[N]; + int INFO; + + DPOSVX(&FACT, &UPLO, &N, &NRHS, A, &LDA, AF, &LDAF, &EQUED, S, B, &LDB, X, &LDX, &RCOND, &FERR, &BERR, WORK, IWORK, &INFO); + + rhs.copyFrom(S); + nlp_->log->write("Scaling S", rhs, hovSummary); + + rhs.copyFrom(X); + delete [] AF; + delete [] S; + delete [] X; + delete [] WORK; + delete [] IWORK; + return 0; +} + +/* this code works fine but requires xblas +int KktLinSysLowRank::solveWithRefin(hiopMatrixDense& M, hiopVectorPar& rhs) +{ + char FACT='E'; + char UPLO='L'; + int N=M.n(); + int NRHS=1; + double* A=M.local_buffer(); + int LDA=N; + double* AF=new double[N*N]; + int LDAF=N; + char EQUED='N'; //it is an output if FACT='E' + double* S = new double[N]; + double* B = rhs.local_data(); + int LDB=N; + double* X = new double[N]; + int LDX = N; + double RCOND, BERR; + double RPVGRW; //Reciprocal pivot growth + int N_ERR_BNDS=3; + double* ERR_BNDS_NORM = new double[NRHS*N_ERR_BNDS]; + double* ERR_BNDS_COMP = new double[NRHS*N_ERR_BNDS]; + int NPARAMS=3; + double PARAMS[NPARAMS]; + PARAMS[0]=1.0; //Use the extra-precise refinement algorithm + PARAMS[1]=3.0; //Maximum number of residual computations allowed for refinement + PARAMS[2]=1.0; //attempt to find a solution with small componentwise + double* WORK = new double[4*N]; + int* IWORK = new int[N]; + int INFO; + + dposvxx_(&FACT, &UPLO, &N, &NRHS, + A, &LDA, + AF, &LDAF, + &EQUED, + S, + B, &LDB, + X, &LDX, + &RCOND, &RPVGRW, &BERR, + &N_ERR_BNDS, ERR_BNDS_NORM, ERR_BNDS_COMP, + &NPARAMS, PARAMS, + WORK, IWORK, + &INFO); + + //rhs.copyFrom(S); + //nlp_->log->write("Scaling S", rhs, hovSummary); + + //M.copyFrom(AF); + //nlp_->log->write("Factoriz ", M, hovSummary); + + printf("INFO ===== %d RCOND=%g RPVGRW=%g BERR=%g EQUED=%c\n", INFO, RCOND, RPVGRW, BERR, EQUED); + printf(" ERR_BNDS_NORM=%g %g %g ERR_BNDS_COMP=%g %g %g \n", ERR_BNDS_NORM[0], ERR_BNDS_NORM[1], ERR_BNDS_NORM[2], ERR_BNDS_COMP[0], ERR_BNDS_COMP[1], ERR_BNDS_COMP[2]); + printf(" PARAMS=%g %g %g \n", PARAMS[0], PARAMS[1], PARAMS[2]); + + + rhs.copyFrom(X); + delete [] AF; + delete [] S; + delete [] X; + delete [] ERR_BNDS_NORM; + delete [] ERR_BNDS_COMP; + delete [] WORK; + delete [] IWORK; + return 0; +} +*/ + +#ifdef HIOP_DEEPCHECKS + +double KktLinSysLowRank::errorCompressedLinsys(const hiopVector& rx, + const hiopVector& ryc, + const hiopVector& ryd, + const hiopVector& dx, + const hiopVector& dyc, + const hiopVector& dyd) +{ + nlp_->log->printf(hovLinAlgScalars, "KktLinSysLowRank::errorCompressedLinsys residuals norm:\n"); + auto* hess_low_rank = dynamic_cast(Hess_); + + double derr = -1.; + double aux; + hiopVector* RX = rx.new_copy(); + //RX=rx-H*dx-J'c*dyc-J'*dyd + hess_low_rank->timesVec(1.0, *RX, -1.0, dx); + //RX->axzpy(-1.0,*Dx,dx); + Jac_c_->transTimesVec(1.0, *RX, -1.0, dyc); + Jac_d_->transTimesVec(1.0, *RX, -1.0, dyd); + aux = RX->twonorm(); + derr = fmax(derr,aux); + nlp_->log->printf(hovLinAlgScalars, " >>> rx=%g\n", aux); + delete RX; + + hiopVector* RC = ryc.new_copy(); + Jac_c_->timesVec(1.0,*RC, -1.0,dx); + aux = RC->twonorm(); + derr = fmax(derr,aux); + nlp_->log->printf(hovLinAlgScalars, " >>> ryc=%g\n", aux); + delete RC; + + hiopVector* RD = ryd.new_copy(); + Jac_d_->timesVec(1.0,*RD, -1.0, dx); + RD->axzpy(1.0, *Dd_inv_, dyd); + aux = RD->twonorm(); + derr=fmax(derr,aux); + nlp_->log->printf(hovLinAlgScalars, " >>> ryd=%g\n", aux); + delete RD; + + return derr; +} + +double KktLinSysLowRank::solveError(const hiopMatrixDense& M, const hiopVector& x, hiopVector& rhs) +{ + double relError; + M.timesVec(1.0,rhs,-1.0,x); + double resnorm = rhs.infnorm(); + + relError=resnorm;// / (1+rhsnorm); + return relError; +} +#endif + +} //end namespace diff --git a/src/Optimization/KktLinSysLowRank.hpp b/src/Optimization/KktLinSysLowRank.hpp new file mode 100644 index 00000000..eb08259f --- /dev/null +++ b/src/Optimization/KktLinSysLowRank.hpp @@ -0,0 +1,169 @@ +// Copyright (c) 2017, Lawrence Livermore National Security, LLC. +// Produced at the Lawrence Livermore National Laboratory (LLNL). +// LLNL-CODE-742473. All rights reserved. +// +// This file is part of HiOp. For details, see https://github.com/LLNL/hiop. HiOp +// is released under the BSD 3-clause license (https://opensource.org/licenses/BSD-3-Clause). +// Please also read “Additional BSD Notice” below. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// i. Redistributions of source code must retain the above copyright notice, this list +// of conditions and the disclaimer below. +// ii. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the disclaimer (as noted below) in the documentation and/or +// other materials provided with the distribution. +// iii. Neither the name of the LLNS/LLNL nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written +// permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +// SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Additional BSD Notice +// 1. This notice is required to be provided under our contract with the U.S. Department +// of Energy (DOE). This work was produced at Lawrence Livermore National Laboratory under +// Contract No. DE-AC52-07NA27344 with the DOE. +// 2. Neither the United States Government nor Lawrence Livermore National Security, LLC +// nor any of their employees, makes any warranty, express or implied, or assumes any +// liability or responsibility for the accuracy, completeness, or usefulness of any +// information, apparatus, product, or process disclosed, or represents that its use would +// not infringe privately-owned rights. +// 3. Also, reference herein to any specific commercial products, process, or services by +// trade name, trademark, manufacturer or otherwise does not necessarily constitute or +// imply its endorsement, recommendation, or favoring by the United States Government or +// Lawrence Livermore National Security, LLC. The views and opinions of authors expressed +// herein do not necessarily state or reflect those of the United States Government or +// Lawrence Livermore National Security, LLC, and shall not be used for advertising or +// product endorsement purposes. + +/** + * @file KktLinSysLowRank.hpp + * + * @author Cosmin G. Petra , LLNL + * + */ + +#ifndef HIOP_KKTLINSYSY_LOWRANK +#define HIOP_KKTLINSYSY_LOWRANK + +#include "hiopKKTLinSys.hpp" + +namespace hiop +{ + +/** + * @brief Encapsulates solves with the KKT system of IPM filter. + * + * This class is for problems where the Hessian of the Lagrangian is a or is approximated + * by low-rank matrix plus a multiple of identity and the number of the constraints is not + * too large. + * + * It works with Hessian being a HessianDiagPlusLowRank class and the constraints Jacobian + * being hiopMatrixDense. + * + * This class solves the XYcYd compression of the full KKT. See solveCompressed method + * for details on the approach used to solve the linear system. + */ + +class KktLinSysLowRank : public hiopKKTLinSysCompressedXYcYd +{ +public: + KktLinSysLowRank(hiopNlpFormulation* nlp); + virtual ~KktLinSysLowRank(); + + /// @brief Updates the KKT system with new info at current iteration + bool update(const hiopIterate* iter, + const hiopVector* grad_f, + const hiopMatrix* Jac_c, + const hiopMatrix* Jac_d, + hiopMatrix* Hess) + { + const hiopMatrixDense* Jac_c_ = dynamic_cast(Jac_c); + const hiopMatrixDense* Jac_d_ = dynamic_cast(Jac_d); + HessianDiagPlusRowRank* Hess_ = dynamic_cast(Hess); + if(Jac_c_==nullptr || Jac_d_==nullptr || Hess_==nullptr) { + assert(false); + return false; + } + return update(iter, grad_f_, Jac_c_, Jac_d_, Hess_); + } + + /// @brief Updates the KKT system with new info at current iteration + virtual bool update(const hiopIterate* iter, + const hiopVector* grad_f, + const hiopMatrixDense* Jac_c, + const hiopMatrixDense* Jac_d, + HessianDiagPlusRowRank* Hess); + + virtual bool build_kkt_matrix(const hiopPDPerturbation& pdreg) + { + assert(false && "not yet implemented"); + return false; + } + + /** + * Solves the compressed linear system, part of the KKT Linear System interface + * + * Solves the system corresponding to directions for x, yc, and yd, namely + * [ H_BFGS + Dx Jc^T Jd^T ] [ dx] [ rx ] + * [ Jc 0 0 ] [dyc] = [ ryc] + * [ Jd 0 -Dd^{-1}] [dyd] [ ryd] + * + * This is done by forming and solving + * [ Jc*(H+Dx)^{-1}*Jc^T Jc*(H+Dx)^{-1}*Jd^T ] [dyc] = [ Jc(H+Dx)^{-1} rx - ryc ] + * [ Jd*(H+Dx)^{-1}*Jc^T Jd*(H+Dx)^{-1}*Jd^T + Dd^{-1}] [dyd] [ Jd(H+dx)^{-1} rx - ryd ] + * and then solving for dx from + * dx = - (H+Dx)^{-1}*(Jc^T*dyc+Jd^T*dyd - rx) + * + */ + virtual bool solveCompressed(hiopVector& rx, + hiopVector& ryc, + hiopVector& ryd, + hiopVector& dx, + hiopVector& dyc, + hiopVector& dyd); + + //LAPACK wrappers + int solve(hiopMatrixDense& M, hiopVector& rhs); + int solveWithRefin(hiopMatrixDense& M, hiopVector& rhs); +#ifdef HIOP_DEEPCHECKS + static double solveError(const hiopMatrixDense& M, const hiopVector& x, hiopVector& rhs); + double errorCompressedLinsys(const hiopVector& rx, + const hiopVector& ryc, + const hiopVector& ryd, + const hiopVector& dx, + const hiopVector& dyc, + const hiopVector& dyd); +protected: + /// @brief perform y=beta*y+alpha*H*x without the log barrier term from H + void HessianTimesVec_noLogBarrierTerm(double beta, hiopVector& y, double alpha, const hiopVector& x) + { + HessianDiagPlusRowRank* hesslowrank = dynamic_cast(Hess_); + assert(nullptr != hesslowrank); + hesslowrank->times_vec_no_logbar_term(beta, y, alpha, x); + } +#endif + +private: + /// The kxk reduced matrix + hiopMatrixDense* N_; +#ifdef HIOP_DEEPCHECKS + /// A copy of the above to compute the residual + hiopMatrixDense* Nmat_; +#endif + //internal buffers: k is usually 2 x quasi-Newton memory; n is the size of primal variable vector + hiopMatrixDense* kxn_mat_; + hiopVector* k_vec1_; +}; +} //end namespace + +#endif // HIOP_KKTLINSYSY_LOWRANK diff --git a/src/Optimization/hiopAlgFilterIPM.cpp b/src/Optimization/hiopAlgFilterIPM.cpp index 973c6d47..4d13f9d8 100644 --- a/src/Optimization/hiopAlgFilterIPM.cpp +++ b/src/Optimization/hiopAlgFilterIPM.cpp @@ -56,6 +56,7 @@ #include "hiopAlgFilterIPM.hpp" #include "hiopKKTLinSys.hpp" +#include "KktLinSysLowRank.hpp" #include "hiopKKTLinSysDense.hpp" #include "hiopKKTLinSysMDS.hpp" #include "hiopKKTLinSysSparse.hpp" @@ -970,7 +971,7 @@ hiopSolveStatus hiopAlgFilterIPMQuasiNewton::run() resetSolverStatus(); //types of linear algebra objects are known now - hiopHessianLowRank* Hess = dynamic_cast(_Hess_Lagr); + auto* Hess = dynamic_cast(_Hess_Lagr); nlp->runStats.initialize(); nlp->runStats.kkt.initialize(); @@ -1047,7 +1048,7 @@ hiopSolveStatus hiopAlgFilterIPMQuasiNewton::run() theta_max = theta_max_fact_*fmax(1.0,resid->get_theta()); theta_min = theta_min_fact_*fmax(1.0,resid->get_theta()); - hiopKKTLinSysLowRank* kkt=new hiopKKTLinSysLowRank(nlp); + KktLinSysLowRank* kkt = new KktLinSysLowRank(nlp); assert(kkt != nullptr); // assign an Null pd_perturb, i.e., all the deltas = 0.0 @@ -1598,12 +1599,12 @@ void hiopAlgFilterIPMQuasiNewton::save_state_to_sidre_group(::axom::sidre::Group SidreHelper::copy_iterate_to_views(group, "alg_iterate_", *it_curr); //state of quasi-Newton Hessian approximation - hiopHessianLowRank& hqn = dynamic_cast(*_Hess_Lagr); - const double hqn_params[] = {(double)hqn.l_max, - (double)hqn.l_curr, - hqn.sigma, - hqn.sigma0, - (double)hqn.matrixChanged}; + HessianDiagPlusRowRank& hqn = dynamic_cast(*_Hess_Lagr); + const double hqn_params[] = {(double)hqn.l_max_, + (double)hqn.l_curr_, + hqn.sigma_, + hqn.sigma0_, + (double)hqn.matrix_changed_}; const size_type nhqn_params = sizeof(hqn_params) / sizeof(double); SidreHelper::copy_array_to_view(group, "Hess_quasiNewton_params", hqn_params, nhqn_params); @@ -1711,7 +1712,7 @@ void hiopAlgFilterIPMQuasiNewton::load_state_from_sidre_group(const sidre::Group // //state of quasi-Newton Hessian approximation // - hiopHessianLowRank& hqn = dynamic_cast(*_Hess_Lagr); + HessianDiagPlusRowRank& hqn = dynamic_cast(*_Hess_Lagr); //!!!note: nparams needs to match the # of params from save_state_to_sidre_group const int nhqn_params = 5; double hqn_params[nhqn_params]; @@ -1721,11 +1722,11 @@ void hiopAlgFilterIPMQuasiNewton::load_state_from_sidre_group(const sidre::Group //ensure the internals are allocated for this mem length hqn.alloc_for_limited_mem(lim_mem_length); - hqn.l_max = (size_type) hqn_params[0]; - hqn.l_curr = lim_mem_length; - hqn.sigma = hqn_params[2]; - hqn.sigma0 = hqn_params[3]; - hqn.matrixChanged = hqn_params[4]; + hqn.l_max_ = (size_type) hqn_params[0]; + hqn.l_curr_ = lim_mem_length; + hqn.sigma_ = hqn_params[2]; + hqn.sigma0_ = hqn_params[3]; + hqn.matrix_changed_ = hqn_params[4]; assert(hqn.it_prev_); //quasi-Newton Hessian stores the previous iterate and corresponding derivatives diff --git a/src/Optimization/hiopAlgFilterIPM.hpp b/src/Optimization/hiopAlgFilterIPM.hpp index bf90fa97..10653bbe 100644 --- a/src/Optimization/hiopAlgFilterIPM.hpp +++ b/src/Optimization/hiopAlgFilterIPM.hpp @@ -60,7 +60,7 @@ #include "hiopIterate.hpp" #include "hiopResidual.hpp" #include "hiopFilter.hpp" -#include "hiopHessianLowRank.hpp" +#include "HessianDiagPlusRowRank.hpp" #include "hiopKKTLinSys.hpp" #include "hiopLogBarProblem.hpp" #include "hiopDualsUpdater.hpp" diff --git a/src/Optimization/hiopIterate.cpp b/src/Optimization/hiopIterate.cpp index 2cff027f..b4791397 100644 --- a/src/Optimization/hiopIterate.cpp +++ b/src/Optimization/hiopIterate.cpp @@ -1,6 +1,5 @@ // Copyright (c) 2017, Lawrence Livermore National Security, LLC. // Produced at the Lawrence Livermore National Laboratory (LLNL). -// Written by Cosmin G. Petra, petra1@llnl.gov. // LLNL-CODE-742473. All rights reserved. // // This file is part of HiOp. For details, see https://github.com/LLNL/hiop. HiOp @@ -46,6 +45,14 @@ // Lawrence Livermore National Security, LLC, and shall not be used for advertising or // product endorsement purposes. +/** + * @file hiopIterate.cpp + * + * @author Cosmin G. Petra , LLNL + * @author Nai-Yuan Chiang , LLNL + * + */ + #include "hiopIterate.hpp" #include diff --git a/src/Optimization/hiopIterate.hpp b/src/Optimization/hiopIterate.hpp index 8c4ce5dc..6e0e3e0e 100644 --- a/src/Optimization/hiopIterate.hpp +++ b/src/Optimization/hiopIterate.hpp @@ -1,6 +1,5 @@ // Copyright (c) 2017, Lawrence Livermore National Security, LLC. // Produced at the Lawrence Livermore National Laboratory (LLNL). -// Written by Cosmin G. Petra, petra1@llnl.gov. // LLNL-CODE-742473. All rights reserved. // // This file is part of HiOp. For details, see https://github.com/LLNL/hiop. HiOp @@ -46,6 +45,14 @@ // Lawrence Livermore National Security, LLC, and shall not be used for advertising or // product endorsement purposes. +/** + * @file hiopIterate.hpp + * + * @author Cosmin G. Petra , LLNL + * @author Nai-Yuan Chiang , LLNL + * + */ + #ifndef HIOP_ITERATE #define HIOP_ITERATE @@ -165,10 +172,9 @@ class hiopIterate friend class hiopKKTLinSysCompressedXDYcYd; friend class hiopKKTLinSysDenseXYcYd; friend class hiopKKTLinSysDenseXDYcYd; - friend class hiopKKTLinSysLowRank; - friend class hiopHessianLowRank; + friend class KktLinSysLowRank; + friend class HessianDiagPlusRowRank; friend class hiopKKTLinSysCompressedMDSXYcYd; - friend class hiopHessianInvLowRank_obsolette; friend class hiopKKTLinSysSparse; friend class hiopKKTLinSysCompressedSparseXYcYd; friend class hiopKKTLinSysCompressedSparseXDYcYd; diff --git a/src/Optimization/hiopKKTLinSys.cpp b/src/Optimization/hiopKKTLinSys.cpp index d91a3d64..a2704909 100644 --- a/src/Optimization/hiopKKTLinSys.cpp +++ b/src/Optimization/hiopKKTLinSys.cpp @@ -1022,499 +1022,6 @@ errorCompressedLinsys(const hiopVector& rx, const hiopVector& rd, #endif -//////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////// -// hiopKKTLinSysLowRank -//////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////// - -hiopKKTLinSysLowRank::hiopKKTLinSysLowRank(hiopNlpFormulation* nlp) - : hiopKKTLinSysCompressedXYcYd(nlp) -{ - nlpD = dynamic_cast(nlp_); - - _kxn_mat = nlpD->alloc_multivector_primal(nlpD->m()); //!opt - assert("DEFAULT" == toupper(nlpD->options->GetString("mem_space"))); - N = LinearAlgebraFactory::create_matrix_dense(nlpD->options->GetString("mem_space"), - nlpD->m(), - nlpD->m()); -#ifdef HIOP_DEEPCHECKS - Nmat=N->alloc_clone(); -#endif - _k_vec1 = dynamic_cast(nlpD->alloc_dual_vec()); -} - -hiopKKTLinSysLowRank::~hiopKKTLinSysLowRank() -{ - if(N) delete N; -#ifdef HIOP_DEEPCHECKS - if(Nmat) delete Nmat; -#endif - if(_kxn_mat) delete _kxn_mat; - if(_k_vec1) delete _k_vec1; -} - -bool hiopKKTLinSysLowRank:: -update(const hiopIterate* iter, - const hiopVector* grad_f, - const hiopMatrixDense* Jac_c, const hiopMatrixDense* Jac_d, - hiopHessianLowRank* Hess) -{ - nlp_->runStats.tmSolverInternal.start(); - - iter_=iter; - grad_f_ = dynamic_cast(grad_f); - Jac_c_ = Jac_c; Jac_d_ = Jac_d; - //Hess = dynamic_cast(Hess_); - Hess_=HessLowRank=Hess; - - //compute the diagonals - //Dx=(Sxl)^{-1}Zl + (Sxu)^{-1}Zu - Dx_->setToZero(); - Dx_->axdzpy_w_pattern(1.0, *iter_->zl, *iter_->sxl, nlp_->get_ixl()); - Dx_->axdzpy_w_pattern(1.0, *iter_->zu, *iter_->sxu, nlp_->get_ixu()); - nlp_->log->write("Dx in KKT", *Dx_, hovMatrices); - - HessLowRank->updateLogBarrierDiagonal(*Dx_); - - //Dd=(Sdl)^{-1}Vu + (Sdu)^{-1}Vu - Dd_inv_->setToZero(); - Dd_inv_->axdzpy_w_pattern(1.0, *iter_->vl, *iter_->sdl, nlp_->get_idl()); - Dd_inv_->axdzpy_w_pattern(1.0, *iter_->vu, *iter_->sdu, nlp_->get_idu()); -#ifdef HIOP_DEEPCHECKS - assert(true==Dd_inv_->allPositive()); -#endif - Dd_->copyFrom(*Dd_inv_); - Dd_inv_->invert(); - - nlp_->runStats.tmSolverInternal.stop(); - - nlp_->log->write("Dd_inv in KKT", *Dd_inv_, hovMatrices); - return true; -} - - -/* Solves the system corresponding to directions for x, yc, and yd, namely - * [ H_BFGS + Dx Jc^T Jd^T ] [ dx] [ rx ] - * [ Jc 0 0 ] [dyc] = [ ryc ] - * [ Jd 0 -Dd^{-1}] [dyd] [ ryd ] - * - * This is done by forming and solving - * [ Jc*(H+Dx)^{-1}*Jc^T Jc*(H+Dx)^{-1}*Jd^T ] [dyc] = [ Jc(H+Dx)^{-1} rx - ryc ] - * [ Jd*(H+Dx)^{-1}*Jc^T Jd*(H+Dx)^{-1}*Jd^T + Dd^{-1}] [dyd] [ Jd(H+dx)^{-1} rx - ryd ] - * and then solving for dx from - * dx = - (H+Dx)^{-1}*(Jc^T*dyc+Jd^T*dyd - rx) - * - * Note that ops H+Dx are provided by hiopHessianLowRank - */ -bool hiopKKTLinSysLowRank:: -solveCompressed(hiopVector& rx, hiopVector& ryc, hiopVector& ryd, - hiopVector& dx, hiopVector& dyc, hiopVector& dyd) -{ -#ifdef HIOP_DEEPCHECKS - //some outputing - nlp_->log->write("KKT Low rank: solve compressed RHS", hovIteration); - nlp_->log->write(" rx: ", rx, hovIteration); nlp_->log->write(" ryc: ", ryc, hovIteration); nlp_->log->write(" ryd: ", ryd, hovIteration); - nlp_->log->write(" Jc: ", *Jac_c_, hovMatrices); - nlp_->log->write(" Jd: ", *Jac_d_, hovMatrices); - nlp_->log->write(" Dd_inv: ", *Dd_inv_, hovMatrices); - assert(Dd_inv_->isfinite_local() && "Something bad happened: nan or inf value"); -#endif - - hiopMatrixDense& J = *_kxn_mat; - const hiopMatrixDense* Jac_c_de = dynamic_cast(Jac_c_); assert(Jac_c_de); - const hiopMatrixDense* Jac_d_de = dynamic_cast(Jac_d_); assert(Jac_d_de); - J.copyRowsFrom(*Jac_c_de, nlp_->m_eq(), 0); //!opt - J.copyRowsFrom(*Jac_d_de, nlp_->m_ineq(), nlp_->m_eq());//!opt - - //N = J*(Hess\J') - //Hess->symmetricTimesMat(0.0, *N, 1.0, J); - HessLowRank->symMatTimesInverseTimesMatTrans(0.0, *N, 1.0, J); - - //subdiag of N += 1., Dd_inv - N->addSubDiagonal(1., nlp_->m_eq(), *Dd_inv_); -#ifdef HIOP_DEEPCHECKS - assert(J.isfinite()); - nlp_->log->write("solveCompressed: N is", *N, hovMatrices); - nlp_->log->write("solveCompressed: rx is", rx, hovMatrices); - nlp_->log->printf(hovLinAlgScalars, "inf norm of Dd_inv is %g\n", Dd_inv_->infnorm()); - N->assertSymmetry(1e-10); -#endif - - //compute the rhs of the lin sys involving N - // 1. first compute (H+Dx)^{-1} rx_tilde and store it temporarily in dx - HessLowRank->solve(rx, dx); -#ifdef HIOP_DEEPCHECKS - assert(rx.isfinite_local() && "Something bad happened: nan or inf value"); - assert(dx.isfinite_local() && "Something bad happened: nan or inf value"); -#endif - - // 2 . then rhs = [ Jc(H+Dx)^{-1}*rx - ryc ] - // [ Jd(H+dx)^{-1}*rx - ryd ] - hiopVector& rhs=*_k_vec1; - rhs.copyFromStarting(0, ryc); - rhs.copyFromStarting(nlp_->m_eq(), ryd); - J.timesVec(-1.0, rhs, 1.0, dx); - -#ifdef HIOP_DEEPCHECKS - nlp_->log->write("solveCompressed: dx sol is", dx, hovMatrices); - nlp_->log->write("solveCompressed: rhs for N is", rhs, hovMatrices); - Nmat->copyFrom(*N); - hiopVector* r=rhs.new_copy(); //save the rhs to check the norm of the residual -#endif - - // - //solve N * dyc_dyd = rhs - // - int ierr = solveWithRefin(*N,rhs); - //int ierr = solve(*N,rhs); - - hiopVector& dyc_dyd= rhs; - dyc_dyd.copyToStarting(0, dyc); - dyc_dyd.copyToStarting(nlp_->m_eq(), dyd); - - //now solve for dx = - (H+Dx)^{-1}*(Jc^T*dyc+Jd^T*dyd - rx) - //first rx = -(Jc^T*dyc+Jd^T*dyd - rx) - J.transTimesVec(1.0, rx, -1.0, dyc_dyd); - //then dx = (H+Dx)^{-1} rx - HessLowRank->solve(rx, dx); - -#ifdef HIOP_DEEPCHECKS - //some outputing - nlp_->log->write("KKT Low rank: solve compressed SOL", hovIteration); - nlp_->log->write(" dx: ", dx, hovIteration); nlp_->log->write(" dyc: ", dyc, hovIteration); nlp_->log->write(" dyd: ", dyd, hovIteration); - delete r; -#endif - - return ierr==0; -} - -int hiopKKTLinSysLowRank::solveWithRefin(hiopMatrixDense& M, hiopVector& rhs) -{ - // 1. Solve dposvx (solve + equilibrating + iterative refinement + forward and backward error estimates) - // 2. Check the residual norm - // 3. If residual norm is not small enough, then perform iterative refinement. This is because dposvx - // does not always provide a small enough residual since it stops (possibly without refinement) based on - // the forward and backward estimates - - int N=M.n(); - if(N<=0) return 0; - - hiopMatrixDense* Aref = M.new_copy(); - hiopVector* rhsref = rhs.new_copy(); - - char FACT='E'; - char UPLO='L'; - - int NRHS=1; - double* A=M.local_data(); - int LDA=N; - double* AF=new double[N*N]; - int LDAF=N; - char EQUED='N'; //it is an output if FACT='E' - double* S = new double[N]; - double* B = rhs.local_data(); - int LDB=N; - double* X = new double[N]; - int LDX = N; - double RCOND, FERR, BERR; - double* WORK = new double[3*N]; - int* IWORK = new int[N]; - int INFO; - - // - // 1. solve - // - DPOSVX(&FACT, &UPLO, &N, &NRHS, - A, &LDA, - AF, &LDAF, - &EQUED, - S, - B, &LDB, - X, &LDX, - &RCOND, &FERR, &BERR, - WORK, IWORK, - &INFO); - //printf("INFO ===== %d RCOND=%g FERR=%g BERR=%g EQUED=%c\n", INFO, RCOND, FERR, BERR, EQUED); - // - // 2. check residual - // - hiopVector* x = rhs.alloc_clone(); - hiopVector* dx = rhs.alloc_clone(); - hiopVector* resid = rhs.alloc_clone(); - int nIterRefin=0;double nrmResid; - int info; - const int MAX_ITER_REFIN=3; - while(true) { - x->copyFrom(X); - resid->copyFrom(*rhsref); - Aref->timesVec(1.0, *resid, -1.0, *x); - - nlp_->log->write("resid", *resid, hovLinAlgScalars); - - nrmResid= resid->infnorm(); - nlp_->log->printf(hovScalars, "hiopKKTLinSysLowRank::solveWithRefin iterrefin=%d residual norm=%g\n", nIterRefin, nrmResid); - - if(nrmResid<1e-8) break; - - if(nIterRefin>=MAX_ITER_REFIN) { - nlp_->log->write("N", *Aref, hovMatrices); - nlp_->log->write("sol", *x, hovMatrices); - nlp_->log->write("rhs", *rhsref, hovMatrices); - - nlp_->log->printf(hovWarning, "hiopKKTLinSysLowRank::solveWithRefin reduced residual to ONLY (inf-norm) %g after %d iterative refinements\n", nrmResid, nIterRefin); - break; - //assert(false && "too many refinements"); - } - if(0) { //iter refin based on symmetric indefinite factorization+solve - - - int _V_ipiv_vec[1000]; double _V_work_vec[1000]; int lwork=1000; - M.copyFrom(*Aref); - DSYTRF(&UPLO, &N, M.local_data(), &LDA, _V_ipiv_vec, _V_work_vec, &lwork, &info); - assert(info==0); - DSYTRS(&UPLO, &N, &NRHS, M.local_data(), &LDA, _V_ipiv_vec, resid->local_data(), &LDB, &info); - assert(info==0); - } else { //iter refin based on symmetric positive definite factorization+solve - M.copyFrom(*Aref); - //for(int i=0; i<4; i++) M.local_data()[i][i] +=1e-8; - DPOTRF(&UPLO, &N, M.local_data(), &LDA, &info); - if(info>0) - nlp_->log->printf(hovError, "hiopKKTLinSysLowRank::factorizeMat: dpotrf (Chol fact) " - "detected %d minor being indefinite.\n", info); - else - if(info<0) - nlp_->log->printf(hovError, "hiopKKTLinSysLowRank::factorizeMat: dpotrf returned " - "error %d\n", info); - - DPOTRS(&UPLO,&N, &NRHS, M.local_data(), &LDA, resid->local_data(), &LDA, &info); - if(info<0) - nlp_->log->printf(hovError, "hiopKKTLinSysLowRank::solveWithFactors: dpotrs returned " - "error %d\n", info); - } - - // //FACT='F'; EQUED='Y'; //reuse the factorization and the equilibration - // M.copyFrom(*Aref); - // A = M.local_buffer(); - // dposvx_(&FACT, &UPLO, &N, &NRHS, - // A, &LDA, - // AF, &LDAF, - // &EQUED, - // S, - // resid.local_data(), &LDB, - // X, &LDX, - // &RCOND, &FERR, &BERR, - // WORK, IWORK, - // &INFO); - // printf("INFO ===== %d RCOND=%g FERR=%g BERR=%g EQUED=%c\n", INFO, RCOND, FERR, BERR, EQUED); - - dx->copyFrom(*resid); - x->axpy(1., *dx); - - nIterRefin++; - } - - rhs.copyFrom(*x); - delete[] AF; - delete[] S; - delete[] X; - delete[] WORK; - delete[] IWORK; - delete Aref; - delete rhsref; - delete x; - delete dx; - delete resid; - -// #ifdef HIOP_DEEPCHECKS -// hiopVectorPar sol(rhs.get_size()); -// hiopVectorPar rhss(rhs.get_size()); -// sol.copyFrom(rhs); rhss.copyFrom(*r); -// double relErr=solveError(*Nmat, rhs, *r); -// if(relErr>1e-5) { -// nlp_->log->printf(hovWarning, "large rel. error (%g) in linear solver occured the Cholesky solve (hiopKKTLinSys)\n", relErr); - -// nlp_->log->write("matrix N=", *Nmat, hovError); -// nlp_->log->write("rhs", rhss, hovError); -// nlp_->log->write("sol", sol, hovError); - -// assert(false && "large error (%g) in linear solve (hiopKKTLinSys), equilibrating the matrix and/or iterative refinement are needed (see dposvx/x)"); -// } else -// if(relErr>1e-16) -// nlp_->log->printf(hovWarning, "considerable rel. error (%g) in linear solver occured the Cholesky solve (hiopKKTLinSys)\n", relErr); - -// nlp_->log->printf(hovLinAlgScalars, "hiopKKTLinSysLowRank::solveCompressed: Cholesky solve: relative error %g\n", relErr); -// delete r; -// #endif - return 0; -} - -int hiopKKTLinSysLowRank::solve(hiopMatrixDense& M, hiopVector& rhs) -{ - char FACT='E'; - char UPLO='L'; - int N=M.n(); - int NRHS=1; - double* A=M.local_data(); - int LDA=N; - double* AF=new double[N*N]; - int LDAF=N; - char EQUED='N'; //it is an output if FACT='E' - double* S = new double[N]; - double* B = rhs.local_data(); - int LDB=N; - double* X = new double[N]; - int LDX = N; - double RCOND, FERR, BERR; - double* WORK = new double[3*N]; - int* IWORK = new int[N]; - int INFO; - - DPOSVX(&FACT, &UPLO, &N, &NRHS, - A, &LDA, - AF, &LDAF, - &EQUED, - S, - B, &LDB, - X, &LDX, - &RCOND, &FERR, &BERR, - WORK, IWORK, - &INFO); - - rhs.copyFrom(S); - nlp_->log->write("Scaling S", rhs, hovSummary); - - //printf("INFO ===== %d RCOND=%g FERR=%g BERR=%g EQUED=%c\n", INFO, RCOND, FERR, BERR, EQUED); - - rhs.copyFrom(X); - delete [] AF; - delete [] S; - delete [] X; - delete [] WORK; - delete [] IWORK; - return 0; -} - -/* this code works fine but requires xblas -int hiopKKTLinSysLowRank::solveWithRefin(hiopMatrixDense& M, hiopVectorPar& rhs) -{ - char FACT='E'; - char UPLO='L'; - int N=M.n(); - int NRHS=1; - double* A=M.local_buffer(); - int LDA=N; - double* AF=new double[N*N]; - int LDAF=N; - char EQUED='N'; //it is an output if FACT='E' - double* S = new double[N]; - double* B = rhs.local_data(); - int LDB=N; - double* X = new double[N]; - int LDX = N; - double RCOND, BERR; - double RPVGRW; //Reciprocal pivot growth - int N_ERR_BNDS=3; - double* ERR_BNDS_NORM = new double[NRHS*N_ERR_BNDS]; - double* ERR_BNDS_COMP = new double[NRHS*N_ERR_BNDS]; - int NPARAMS=3; - double PARAMS[NPARAMS]; - PARAMS[0]=1.0; //Use the extra-precise refinement algorithm - PARAMS[1]=3.0; //Maximum number of residual computations allowed for refinement - PARAMS[2]=1.0; //attempt to find a solution with small componentwise - double* WORK = new double[4*N]; - int* IWORK = new int[N]; - int INFO; - - dposvxx_(&FACT, &UPLO, &N, &NRHS, - A, &LDA, - AF, &LDAF, - &EQUED, - S, - B, &LDB, - X, &LDX, - &RCOND, &RPVGRW, &BERR, - &N_ERR_BNDS, ERR_BNDS_NORM, ERR_BNDS_COMP, - &NPARAMS, PARAMS, - WORK, IWORK, - &INFO); - - //rhs.copyFrom(S); - //nlp_->log->write("Scaling S", rhs, hovSummary); - - //M.copyFrom(AF); - //nlp_->log->write("Factoriz ", M, hovSummary); - - printf("INFO ===== %d RCOND=%g RPVGRW=%g BERR=%g EQUED=%c\n", INFO, RCOND, RPVGRW, BERR, EQUED); - printf(" ERR_BNDS_NORM=%g %g %g ERR_BNDS_COMP=%g %g %g \n", ERR_BNDS_NORM[0], ERR_BNDS_NORM[1], ERR_BNDS_NORM[2], ERR_BNDS_COMP[0], ERR_BNDS_COMP[1], ERR_BNDS_COMP[2]); - printf(" PARAMS=%g %g %g \n", PARAMS[0], PARAMS[1], PARAMS[2]); - - - rhs.copyFrom(X); - delete [] AF; - delete [] S; - delete [] X; - delete [] ERR_BNDS_NORM; - delete [] ERR_BNDS_COMP; - delete [] WORK; - delete [] IWORK; - return 0; -} -*/ - -#ifdef HIOP_DEEPCHECKS - -double hiopKKTLinSysLowRank:: -errorCompressedLinsys(const hiopVector& rx, const hiopVector& ryc, const hiopVector& ryd, - const hiopVector& dx, const hiopVector& dyc, const hiopVector& dyd) -{ - nlp_->log->printf(hovLinAlgScalars, "hiopKKTLinSysLowRank::errorCompressedLinsys residuals norm:\n"); - - double derr=-1., aux; - hiopVector *RX=rx.new_copy(); - //RX=rx-H*dx-J'c*dyc-J'*dyd - HessLowRank->timesVec(1.0, *RX, -1.0, dx); - //RX->axzpy(-1.0,*Dx,dx); - Jac_c_->transTimesVec(1.0, *RX, -1.0, dyc); - Jac_d_->transTimesVec(1.0, *RX, -1.0, dyd); - aux=RX->twonorm(); - derr=fmax(derr,aux); - nlp_->log->printf(hovLinAlgScalars, " >>> rx=%g\n", aux); - // if(aux>1e-8) { - // nlp_->log->write("Low rank Hessian is:", *Hess, hovLinAlgScalars); - // } - delete RX; RX=NULL; - - hiopVector* RC=ryc.new_copy(); - Jac_c_->timesVec(1.0,*RC, -1.0,dx); - aux = RC->twonorm(); - derr=fmax(derr,aux); - nlp_->log->printf(hovLinAlgScalars, " >>> ryc=%g\n", aux); - delete RC; RC=NULL; - - hiopVector* RD=ryd.new_copy(); - Jac_d_->timesVec(1.0,*RD, -1.0, dx); - RD->axzpy(1.0, *Dd_inv_, dyd); - aux = RD->twonorm(); - derr=fmax(derr,aux); - nlp_->log->printf(hovLinAlgScalars, " >>> ryd=%g\n", aux); - delete RD; RD=NULL; - - return derr; -} - -double hiopKKTLinSysLowRank::solveError(const hiopMatrixDense& M, const hiopVector& x, hiopVector& rhs) -{ - double relError; - M.timesVec(1.0,rhs,-1.0,x); - double resnorm=rhs.infnorm(); - - relError=resnorm;// / (1+rhsnorm); - return relError; -} -#endif - - //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// // hiopKKTLinSysFull diff --git a/src/Optimization/hiopKKTLinSys.hpp b/src/Optimization/hiopKKTLinSys.hpp index 83334ba6..98dee25e 100644 --- a/src/Optimization/hiopKKTLinSys.hpp +++ b/src/Optimization/hiopKKTLinSys.hpp @@ -51,7 +51,7 @@ #include "hiopIterate.hpp" #include "hiopResidual.hpp" -#include "hiopHessianLowRank.hpp" +#include "HessianDiagPlusRowRank.hpp" #include "hiopPDPerturbation.hpp" #include "hiopLinSolver.hpp" #include "hiopFactAcceptor.hpp" @@ -382,82 +382,7 @@ class hiopKKTLinSysCompressedXDYcYd : public hiopKKTLinSysCompressed #endif }; -class hiopKKTLinSysLowRank : public hiopKKTLinSysCompressedXYcYd -{ -public: - hiopKKTLinSysLowRank(hiopNlpFormulation* nlp); - virtual ~hiopKKTLinSysLowRank(); - - bool update(const hiopIterate* iter, - const hiopVector* grad_f, - const hiopMatrix* Jac_c, const hiopMatrix* Jac_d, - hiopMatrix* Hess) - { - const hiopMatrixDense* Jac_c_ = dynamic_cast(Jac_c); - const hiopMatrixDense* Jac_d_ = dynamic_cast(Jac_d); - hiopHessianLowRank* Hess_ = dynamic_cast(Hess); - if(Jac_c_==NULL || Jac_d_==NULL || Hess_==NULL) { - assert(false); - return false; - } - return update(iter, grad_f_, Jac_c_, Jac_d_, Hess_); - } - virtual bool update(const hiopIterate* iter, - const hiopVector* grad_f, - const hiopMatrixDense* Jac_c, const hiopMatrixDense* Jac_d, - hiopHessianLowRank* Hess); - - virtual bool build_kkt_matrix(const hiopPDPerturbation& pdreg) - { - assert(false && "not yet implemented"); - return false; - } - - /* Solves the system corresponding to directions for x, yc, and yd, namely - * [ H_BFGS + Dx Jc^T Jd^T ] [ dx] [ rx_tilde ] - * [ Jc 0 0 ] [dyc] = [ ryc ] - * [ Jd 0 -Dd^{-1}] [dyd] [ ryd_tilde] - * - * This is done by forming and solving - * [ Jc*(H+Dx)^{-1}*Jc^T Jc*(H+Dx)^{-1}*Jd^T ] [dyc] = [ Jc(H+Dx)^{-1} rx - ryc ] - * [ Jd*(H+Dx)^{-1}*Jc^T Jd*(H+Dx)^{-1}*Jd^T + Dd^{-1}] [dyd] [ Jd(H+dx)^{-1} rx - ryd ] - * and then solving for dx from - * dx = - (H+Dx)^{-1}*(Jc^T*dyc+Jd^T*dyd - rx) - * - */ - virtual bool solveCompressed(hiopVector& rx, hiopVector& ryc, hiopVector& ryd, - hiopVector& dx, hiopVector& dyc, hiopVector& dyd); - - //LAPACK wrappers - int solve(hiopMatrixDense& M, hiopVector& rhs); - int solveWithRefin(hiopMatrixDense& M, hiopVector& rhs); -#ifdef HIOP_DEEPCHECKS - static double solveError(const hiopMatrixDense& M, const hiopVector& x, hiopVector& rhs); - double errorCompressedLinsys(const hiopVector& rx, const hiopVector& ryc, const hiopVector& ryd, - const hiopVector& dx, const hiopVector& dyc, const hiopVector& dyd); -protected: - //y=beta*y+alpha*H*x - void HessianTimesVec_noLogBarrierTerm(double beta, hiopVector& y, double alpha, const hiopVector& x) - { - hiopHessianLowRank* HessLowR = dynamic_cast(Hess_); - assert(NULL != HessLowR); - if(HessLowR) HessLowR->timesVec_noLogBarrierTerm(beta, y, alpha, x); - } -#endif - -private: - hiopNlpDenseConstraints* nlpD; - hiopHessianLowRank* HessLowRank; - - hiopMatrixDense* N; //the kxk reduced matrix -#ifdef HIOP_DEEPCHECKS - hiopMatrixDense* Nmat; //a copy of the above to compute the residual -#endif - //internal buffers - hiopMatrixDense* _kxn_mat; //!opt (work directly with the Jacobian) - hiopVector* _k_vec1; -}; /* diff --git a/src/Optimization/hiopNlpFormulation.cpp b/src/Optimization/hiopNlpFormulation.cpp index 5204681d..7ffb404d 100644 --- a/src/Optimization/hiopNlpFormulation.cpp +++ b/src/Optimization/hiopNlpFormulation.cpp @@ -54,7 +54,7 @@ */ #include "hiopNlpFormulation.hpp" -#include "hiopHessianLowRank.hpp" +#include "HessianDiagPlusRowRank.hpp" #include "hiopVector.hpp" #include "LinAlgFactory.hpp" #include "hiopLogger.hpp" @@ -1636,7 +1636,7 @@ hiopMatrixDense* hiopNlpDenseConstraints::alloc_Jac_cons() hiopMatrix* hiopNlpDenseConstraints::alloc_Hess_Lagr() { - return new hiopHessianLowRank(this, this->options->GetInteger("secant_memory_len")); + return new HessianDiagPlusRowRank(this, this->options->GetInteger("secant_memory_len")); } hiopMatrixDense* hiopNlpDenseConstraints::alloc_multivector_primal(int nrows, int maxrows/*=-1*/) const diff --git a/src/Optimization/hiopNlpFormulation.hpp b/src/Optimization/hiopNlpFormulation.hpp index ed522f4d..a9467ae5 100644 --- a/src/Optimization/hiopNlpFormulation.hpp +++ b/src/Optimization/hiopNlpFormulation.hpp @@ -461,7 +461,7 @@ class hiopNlpDenseConstraints : public hiopNlpFormulation virtual hiopMatrixDense* alloc_Jac_c(); virtual hiopMatrixDense* alloc_Jac_d(); virtual hiopMatrixDense* alloc_Jac_cons(); - //returns hiopHessianLowRank which (fakely) inherits from hiopMatrix + //returns HessianDiagPlusRowRank which (fakely) inherits from hiopMatrix virtual hiopMatrix* alloc_Hess_Lagr(); /* this is in general for a dense matrix with n_vars cols and a small number of diff --git a/src/Utils/hiopLogger.cpp b/src/Utils/hiopLogger.cpp index 29d3452a..705c19e0 100644 --- a/src/Utils/hiopLogger.cpp +++ b/src/Utils/hiopLogger.cpp @@ -50,7 +50,7 @@ #include "hiopVector.hpp" #include "hiopResidual.hpp" -#include "hiopHessianLowRank.hpp" +#include "HessianDiagPlusRowRank.hpp" #include "hiopFilter.hpp" #include "hiopOptions.hpp" @@ -97,7 +97,10 @@ void hiopLogger::write(const char* msg, const hiopIterate& it, hiopOutVerbosity } #ifdef HIOP_DEEPCHECKS -void hiopLogger::write(const char* msg, const hiopHessianLowRank& Hess, hiopOutVerbosity v, int loggerid/*=0*/) +void hiopLogger::write(const char* msg, + const HessianDiagPlusRowRank& Hess, + hiopOutVerbosity v, + int loggerid/*=0*/) { if(master_rank_ != my_rank_) return; hiopOutVerbosity _verb = (hiopOutVerbosity) options_->GetInteger("verbosity_level"); @@ -106,7 +109,7 @@ void hiopLogger::write(const char* msg, const hiopHessianLowRank& Hess, hiopOutV } #endif -void hiopLogger::write(const char* msg, const hiopOptions& options, hiopOutVerbosity v, int loggerid/*=0*/) +void hiopLogger::write(const char* msg, const hiopOptions& options, hiopOutVerbosity v, int loggerid/*=0*/) { if(master_rank_ != my_rank_) return; hiopOutVerbosity _verb = (hiopOutVerbosity) options_->GetInteger("verbosity_level"); diff --git a/src/Utils/hiopLogger.hpp b/src/Utils/hiopLogger.hpp index 2b211179..8bb68e52 100644 --- a/src/Utils/hiopLogger.hpp +++ b/src/Utils/hiopLogger.hpp @@ -62,7 +62,7 @@ class hiopVector; class hiopResidual; class hiopIterate; class hiopMatrix; -class hiopHessianLowRank; +class HessianDiagPlusRowRank; class hiopNlpFormulation; class hiopOptions; class hiopFilter; @@ -105,7 +105,7 @@ class hiopLogger void write(const char* msg, const hiopIterate& r, hiopOutVerbosity v, int loggerid=0); void write(const char* msg, const hiopMatrix& M, hiopOutVerbosity v, int loggerid=0); #ifdef HIOP_DEEPCHECKS - void write(const char* msg, const hiopHessianLowRank& Hess, hiopOutVerbosity v, int loggerid=0); + void write(const char* msg, const HessianDiagPlusRowRank& Hess, hiopOutVerbosity v, int loggerid=0); #endif void write(const char* msg, const hiopNlpFormulation& nlp, hiopOutVerbosity v, int loggerid=0); void write(const char* msg, const hiopOptions& options, hiopOutVerbosity v, int loggerid=0);