|
ConstrainedOptPack: C++ Tools for Constrained (and Unconstrained) Optimization Version of the Day
|
00001 #if 0 00002 00003 // @HEADER 00004 // *********************************************************************** 00005 // 00006 // Moocho: Multi-functional Object-Oriented arCHitecture for Optimization 00007 // Copyright (2003) Sandia Corporation 00008 // 00009 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive 00010 // license for use of this work by or on behalf of the U.S. Government. 00011 // 00012 // This library is free software; you can redistribute it and/or modify 00013 // it under the terms of the GNU Lesser General Public License as 00014 // published by the Free Software Foundation; either version 2.1 of the 00015 // License, or (at your option) any later version. 00016 // 00017 // This library is distributed in the hope that it will be useful, but 00018 // WITHOUT ANY WARRANTY; without even the implied warranty of 00019 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00020 // Lesser General Public License for more details. 00021 // 00022 // You should have received a copy of the GNU Lesser General Public 00023 // License along with this library; if not, write to the Free Software 00024 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00025 // USA 00026 // Questions? Contact Roscoe A. Bartlett (rabartl@sandia.gov) 00027 // 00028 // *********************************************************************** 00029 // @HEADER 00030 00031 #include "ConstrainedOptPack_MatrixHessianSuperBasic.hpp" 00032 #include "ConstrainedOptPack_initialize_Q_R_Q_X.hpp" 00033 #include "AbstractLinAlgPack_GenPermMatrixSliceOp.hpp" 00034 #include "AbstractLinAlgPack/src/AbstractLinAlgPack_SpVectorClass.hpp" 00035 #include "AbstractLinAlgPack_SpVectorOp.hpp" 00036 #include "AbstractLinAlgPack/src/AbstractLinAlgPack_MatrixOpOut.hpp" 00037 #include "DenseLinAlgPack_DVectorClass.hpp" 00038 #include "DenseLinAlgPack_LinAlgOpPack.hpp" 00039 #include "DenseLinAlgPack_AssertOp.hpp" 00040 00041 namespace LinAlgOpPack { 00042 using AbstractLinAlgPack::Vp_StMtV; 00043 } 00044 00045 namespace ConstrainedOptPack { 00046 00047 MatrixHessianSuperBasic::MatrixHessianSuperBasic() 00048 : n_(0) 00049 {} 00050 00051 void MatrixHessianSuperBasic::initialize( 00052 size_type n 00053 ,size_type n_R 00054 ,const size_type i_x_free[] 00055 ,const size_type i_x_fixed[] 00056 ,const EBounds bnd_fixed[] 00057 ,const B_RR_ptr_t& B_RR_ptr 00058 ,const B_RX_ptr_t& B_RX_ptr 00059 ,BLAS_Cpp::Transp B_RX_trans 00060 ,const B_XX_ptr_t& B_XX_ptr 00061 ) 00062 { 00063 using DenseLinAlgPack::Mp_M_assert_sizes; 00064 using BLAS_Cpp::no_trans; 00065 00066 const size_type 00067 n_X = n - n_R; 00068 00069 // Validate input arguments 00070 00071 // i_x_free 00072 if( 0 < n_R && n_R < n && i_x_free == NULL ) { 00073 throw std::invalid_argument( 00074 "MatrixHessianSuperBasic::initialize(...) : Error, " 00075 "i_x_free can not be NULL when 0 < n_R < n" ); 00076 } 00077 // i_x_fixed 00078 if( 0 < n_X && n_X < n && i_x_fixed == NULL ) { 00079 throw std::invalid_argument( 00080 "MatrixHessianSuperBasic::initialize(...) : Error, " 00081 "i_x_fixed can not be NULL when 0 < n-n_R < n" ); 00082 } 00083 // bnd_fixed 00084 if( 0 < n_X && bnd_fixed == NULL ) { 00085 throw std::invalid_argument( 00086 "MatrixHessianSuperBasic::initialize(...) : Error, " 00087 "bnd_fixed can not be NULL when 0 < n-n_R" ); 00088 } 00089 // B_RR 00090 if(n_R > 0 ) { 00091 if( !B_RR_ptr.get() ) 00092 throw std::invalid_argument( 00093 "MatrixHessianSuperBasic::initialize(...) : Error, " 00094 "B_RR_ptr.get() can not be NULL when n_R > 0" ); 00095 Mp_M_assert_sizes( n_R, n_R, no_trans, B_RR_ptr->rows(), B_RR_ptr->cols(), no_trans ); 00096 } 00097 // op(B_RX) 00098 if( n_R < n ) { 00099 if( B_RX_ptr.get() ) { 00100 Mp_M_assert_sizes( n_R, n_X, no_trans, B_RX_ptr->rows(), B_RX_ptr->cols(), B_RX_trans ); 00101 } 00102 } 00103 // B_XX 00104 if( n_R < n ) { 00105 if( !B_XX_ptr.get() ) 00106 throw std::invalid_argument( 00107 "MatrixHessianSuperBasic::initialize(...) : Error, " 00108 "B_XX_ptr.get() can not be NULL if n_R < n" ); 00109 Mp_M_assert_sizes( n_X, n_X, no_trans, B_XX_ptr->rows(), B_XX_ptr->cols(), no_trans ); 00110 } 00111 00112 // Setup Q_R and Q_X and validate i_x_free[] and i_x_fixed[] 00113 const bool Q_R_is_idenity = (n_R == n && i_x_fixed == NULL ); 00114 if( Q_R_is_idenity ) { 00115 Q_R_row_i_.resize(0); 00116 Q_R_col_j_.resize(0); 00117 } 00118 else { 00119 Q_R_row_i_.resize(n_R); 00120 Q_R_col_j_.resize(n_R); 00121 } 00122 Q_X_row_i_.resize(n_X); 00123 Q_X_col_j_.resize(n_X); 00124 bool test_setup = true; // ToDo: Make this an input parameter! 00125 initialize_Q_R_Q_X( 00126 n_R,n_X,i_x_free,i_x_fixed,test_setup 00127 ,!Q_R_is_idenity ? &Q_R_row_i_[0] : NULL 00128 ,!Q_R_is_idenity ? &Q_R_col_j_[0] : NULL 00129 ,&Q_R_ 00130 ,n_X ? &Q_X_row_i_[0] : NULL 00131 ,n_X ? &Q_X_col_j_[0] : NULL 00132 ,&Q_X_ 00133 ); 00134 00135 // Setup bnd_fixed 00136 bnd_fixed_.resize(n_X); 00137 {for(size_type i = 0; i < n_X; ++i) bnd_fixed_[i] = bnd_fixed[i]; } 00138 00139 // Set the rest of the arguments 00140 n_ = n; 00141 n_R_ = n_R; 00142 B_RR_ptr_ = B_RR_ptr; 00143 B_RX_ptr_ = B_RX_ptr; 00144 B_RX_trans_ = B_RX_trans; 00145 B_XX_ptr_ = B_XX_ptr; 00146 00147 } 00148 00149 // Overridden from Matrix 00150 00151 size_type MatrixHessianSuperBasic::rows() const 00152 { 00153 return n_; 00154 } 00155 00156 // Overridden from MatrixOp 00157 00158 void MatrixHessianSuperBasic::Vp_StMtV( 00159 DVectorSlice* y, value_type a, BLAS_Cpp::Transp B_trans 00160 , const DVectorSlice& x, value_type b 00161 ) const 00162 { 00163 using BLAS_Cpp::no_trans; 00164 using BLAS_Cpp::trans; 00165 using BLAS_Cpp::trans_not; 00166 using AbstractLinAlgPack::V_MtV; 00167 using LinAlgOpPack::V_MtV; 00168 assert_initialized(); 00169 DenseLinAlgPack::Vp_MtV_assert_sizes( y->size(), n_, n_, B_trans, x.size() ); 00170 if( n_ == n_R_ ) { 00171 // 00172 // B = Q_R*B_RR*Q_R' 00173 // 00174 // y = b*y + a*Q_R*B_RR*Q_R'*x 00175 // 00176 if( Q_R().is_identity() ) { 00177 AbstractLinAlgPack::Vp_StMtV(y,a,*this->B_RR_ptr(),no_trans,x,b); 00178 } 00179 else { 00180 DVector Q_R_x; 00181 V_MtV( &Q_R_x, Q_R(), trans, x ); 00182 AbstractLinAlgPack::Vp_StPtMtV(y,a,Q_R(),no_trans,*this->B_RR_ptr(),no_trans,Q_R_x(),b); 00183 } 00184 } 00185 else if( n_R_ == 0 ) { 00186 // 00187 // B = Q_X *B_XX * Q_X' 00188 // 00189 TEST_FOR_EXCEPT(true); // ToDo: Implement this! 00190 } 00191 else { 00192 // 00193 // B = [ Q_R Q_X ] * [ B_RR op(B_RX) ] * [ Q_R' ] 00194 // [ op(B_RX') B_XX ] [ Q_X' ] 00195 // 00196 // y = b*y + a*op(B)*x 00197 // 00198 // y = b*y + a * [ Q_R Q_X ] * [ B_RR op(B_RX) ] * [ Q_R' ] * x 00199 // [ op(B_RX') B_XX ] [ Q_X' ] 00200 // 00201 // y = b*y + a*Q_R*B_RR*x_R + a*Q_R*op(B_RX)*x_X 00202 // + a*Q_X*op(B_RX')*x_R + a*Q_X*B_XX*x_X 00203 // where: 00204 // x_R = Q_R'*x 00205 // x_X = Q_X'*x 00206 // 00207 SpVector 00208 x_R, 00209 x_X; 00210 // x_R = Q_R'*x 00211 V_MtV( &x_R, Q_R(), trans, x ); 00212 // x_X = Q_X'*x 00213 V_MtV( &x_X, Q_X(), trans, x ); 00214 // y = b*y + a*Q_R*B_RR*x_R 00215 AbstractLinAlgPack::Vp_StPtMtV( 00216 y, a, Q_R(), no_trans, *B_RR_ptr(), no_trans, x_R(), b ); 00217 // y += a*Q_R*op(B_RX)*x_X + a*Q_X*op(B_RX')*x_R 00218 if( B_RX_ptr().get() ) { 00219 AbstractLinAlgPack::Vp_StPtMtV( 00220 y, a, Q_R(), no_trans, *B_RX_ptr(), B_RX_trans(), x_X() ); 00221 AbstractLinAlgPack::Vp_StPtMtV( 00222 y, a, Q_X(), no_trans, *B_RX_ptr(), trans_not(B_RX_trans()), x_R() ); 00223 } 00224 // y += a*Q_X*B_XX*x_X 00225 AbstractLinAlgPack::Vp_StPtMtV( 00226 y, a, Q_X(), no_trans, *B_XX_ptr(), no_trans, x_X() ); 00227 } 00228 } 00229 00230 void MatrixHessianSuperBasic::Vp_StMtV( 00231 DVectorSlice* y, value_type a, BLAS_Cpp::Transp B_trans 00232 , const SpVectorSlice& x, value_type b 00233 ) const 00234 { 00235 using BLAS_Cpp::no_trans; 00236 using BLAS_Cpp::trans; 00237 using BLAS_Cpp::trans_not; 00238 using AbstractLinAlgPack::V_MtV; 00239 using LinAlgOpPack::V_MtV; 00240 assert_initialized(); 00241 DenseLinAlgPack::Vp_MtV_assert_sizes( y->size(), n_, n_, B_trans, x.size() ); 00242 if( n_ == n_R_ ) { 00243 // 00244 // B = Q_R*B_RR*Q_R' 00245 // 00246 // y = b*y + a*Q_R*B_RR*Q_R'*x 00247 // 00248 if( Q_R().is_identity() ) { 00249 AbstractLinAlgPack::Vp_StMtV(y,a,*this->B_RR_ptr(),no_trans,x,b); 00250 } 00251 else { 00252 SpVector Q_R_x; 00253 AbstractLinAlgPack::V_MtV( &Q_R_x, Q_R(), trans, x ); 00254 AbstractLinAlgPack::Vp_StPtMtV(y,a,Q_R(),no_trans,*this->B_RR_ptr(),no_trans,Q_R_x(),b); 00255 } 00256 } 00257 else if( n_R_ == 0 ) { 00258 // 00259 // B = Q_X *B_XX * Q_X' 00260 // 00261 TEST_FOR_EXCEPT(true); // ToDo: Implement this! 00262 } 00263 else { 00264 // 00265 // B = [ Q_R Q_X ] * [ B_RR op(B_RX) ] * [ Q_R' ] 00266 // [ op(B_RX') B_XX ] [ Q_X' ] 00267 // 00268 // y = b*y + a*op(B)*x 00269 // 00270 // y = b*y + a * [ Q_R Q_X ] * [ B_RR op(B_RX) ] * [ Q_R' ] * x 00271 // [ op(B_RX') B_XX ] [ Q_X' ] 00272 // 00273 // y = b*y + a*Q_R*B_RR*x_R + a*Q_R*op(B_RX)*x_X 00274 // + a*Q_X*op(B_RX')*x_R + a*Q_X*B_XX*x_X 00275 // where: 00276 // x_R = Q_R'*x 00277 // x_X = Q_X'*x 00278 // 00279 SpVector 00280 x_R, 00281 x_X; 00282 // x_R = Q_R'*x 00283 V_MtV( &x_R, Q_R(), trans, x ); 00284 // x_X = Q_X'*x 00285 V_MtV( &x_X, Q_X(), trans, x ); 00286 // y = b*y + a*Q_R*B_RR*x_R 00287 AbstractLinAlgPack::Vp_StPtMtV( 00288 y, a, Q_R(), no_trans, *B_RR_ptr(), no_trans, x_R(), b ); 00289 // y += a*Q_R*op(B_RX)*x_X + a*Q_X*op(B_RX')*x_R 00290 if( B_RX_ptr().get() ) { 00291 AbstractLinAlgPack::Vp_StPtMtV( 00292 y, a, Q_R(), no_trans, *B_RX_ptr(), B_RX_trans(), x_X() ); 00293 AbstractLinAlgPack::Vp_StPtMtV( 00294 y, a, Q_X(), no_trans, *B_RX_ptr(), trans_not(B_RX_trans()), x_R() ); 00295 } 00296 // y += a*Q_X*B_XX*x_X 00297 AbstractLinAlgPack::Vp_StPtMtV( 00298 y, a, Q_X(), no_trans, *B_XX_ptr(), no_trans, x_X() ); 00299 } 00300 } 00301 00302 void MatrixHessianSuperBasic::Vp_StPtMtV( 00303 DVectorSlice* y, value_type a 00304 , const GenPermMatrixSlice& P, BLAS_Cpp::Transp P_trans 00305 , BLAS_Cpp::Transp M_trans 00306 , const DVectorSlice& x, value_type b ) const 00307 { 00308 using BLAS_Cpp::no_trans; 00309 using BLAS_Cpp::trans; 00310 using BLAS_Cpp::trans_not; 00311 using AbstractLinAlgPack::V_MtV; 00312 using DenseLinAlgPack::Vt_S; 00313 using LinAlgOpPack::V_MtV; 00314 namespace slap = AbstractLinAlgPack; 00315 00316 assert_initialized(); 00317 00318 // 00319 // y = b*y + a * op(P) * B * x 00320 // 00321 // => 00322 // 00323 // y = b*y + a * op(P)*(Q_R*B_RR*Q_R' + Q_R*op(B_RX)*Q_X' + Q_X*op(B_RX')*Q_R + Q_X*B_XX*Q_X')*x 00324 // 00325 // = b*y + a*op(P)*Q_R*B_RR*Q_R'*x + a*op(P)*Q_R*op(B_RX)*Q_X'*x 00326 // + a*op(P)*Q_X*op(B_RX')*Q_R*x + a*op(P)*Q_X*B_XX*Q_X'*x 00327 // 00328 // In order to implement the above as efficiently as possible we need to minimize the 00329 // computations with the constituent matrices. First off we will compute 00330 // Q_RT_x = Q_R'*x (O(n_R)) and Q_XT_x = Q_X'*x (O(n_R)) neglect any terms where 00331 // Q_RT_x.nz() == 0 or Q_XT_x.nz() == 0. We will also determine if op(P)*Q_R == 0 (O(n_R)) 00332 // or op(P)*Q_X == 0 (O(n_X)) and neglect these terms if the are zero. 00333 // Hopefully this work will allow us to skip as many computations as possible. 00334 // 00335 LinAlgOpPack::Vp_MtV_assert_sizes(y->size(),P.rows(),P.cols(),P_trans 00336 , BLAS_Cpp::rows( rows(), cols(), M_trans) ); 00337 LinAlgOpPack::Vp_MtV_assert_sizes( BLAS_Cpp::cols( P.rows(), P.cols(), P_trans) 00338 ,rows(),cols(),M_trans,x.size()); 00339 // Q_R'*x 00340 SpVector Q_RT_x; 00341 if(n_R_) { 00342 slap::V_MtV( &Q_RT_x, Q_R(), trans, x ); 00343 } 00344 // Q_X'*x 00345 SpVector Q_XT_x; 00346 if(n_ > n_R_) { 00347 slap::V_MtV( &Q_XT_x, Q_X(), trans, x ); 00348 } 00349 // op(P)*Q_R overlap 00350 size_type P_Q_R_nz = 0; 00351 AbstractLinAlgPack::intersection( P, P_trans, Q_R(), no_trans, &P_Q_R_nz ); 00352 // op(P)*Q_X overlap 00353 size_type P_Q_X_nz = 0; 00354 AbstractLinAlgPack::intersection( P, P_trans, Q_X(), no_trans, &P_Q_X_nz ); 00355 // y = b*y 00356 if(b==0.0) *y = 0.0; 00357 else if(b!=1.0) Vt_S(y,b); 00358 // 00359 DVector t; // ToDo: use workspace 00360 // y += a*op(P)*Q_R*B_RR*Q_R'*x 00361 if( P_Q_R_nz && Q_RT_x.nz() ) { 00362 t.resize(n_); 00363 slap::Vp_StPtMtV( &t(), 1.0, Q_R(), no_trans, *B_RR_ptr(), no_trans, Q_RT_x() ); 00364 slap::Vp_StMtV( y, a, P, P_trans, t() ); 00365 } 00366 // y += a*op(P)*Q_R*op(B_RX)*Q_X'*x 00367 if( P_Q_R_nz && B_RX_ptr().get() && Q_XT_x.nz() ) { 00368 t.resize(n_); 00369 slap::Vp_StPtMtV( &t(), 1.0, Q_R(), no_trans, *B_RX_ptr(), B_RX_trans(), Q_XT_x() ); 00370 slap::Vp_StMtV( y, a, P, P_trans, t() ); 00371 } 00372 // y += a*op(P)*Q_X*op(B_RX')*Q_R*x 00373 if( P_Q_X_nz && B_RX_ptr().get() && Q_RT_x.nz() ) { 00374 t.resize(n_); 00375 slap::Vp_StPtMtV( &t(), 1.0, Q_X(), no_trans, *B_RX_ptr(), trans_not(B_RX_trans()), Q_RT_x() ); 00376 slap::Vp_StMtV( y, a, P, P_trans, t() ); 00377 } 00378 // y += a*op(P)*Q_X*B_XX*Q_X'*x 00379 if( P_Q_X_nz && Q_XT_x.nz() ) { 00380 t.resize(n_); 00381 slap::Vp_StPtMtV( &t(), 1.0, Q_X(), no_trans, *B_XX_ptr(), no_trans, Q_XT_x() ); 00382 slap::Vp_StMtV( y, a, P, P_trans, t() ); 00383 } 00384 } 00385 00386 value_type MatrixHessianSuperBasic::transVtMtV( 00387 const SpVectorSlice& x1, BLAS_Cpp::Transp B_trans 00388 , const SpVectorSlice& x2 ) const 00389 { 00390 using BLAS_Cpp::no_trans; 00391 using BLAS_Cpp::trans; 00392 assert_initialized(); 00393 DenseLinAlgPack::Vp_MtV_assert_sizes( x1.size(), rows(), cols(), B_trans, x1.size() ); 00394 if( n_ == n_R_ ) { 00395 // 00396 // B = Q_R*B_RR*Q_R' 00397 // 00398 // a = x1'*Q_R*B_RR*Q_R'*x2 00399 // 00400 if( Q_R().is_identity() ) { 00401 return AbstractLinAlgPack::transVtMtV( x1, *B_RR_ptr(), no_trans, x2 ); 00402 } 00403 else { 00404 if( x1.overlap(x2) == DenseLinAlgPack::SAME_MEM ) { 00405 SpVector Q_RT_x2; 00406 AbstractLinAlgPack::V_MtV( &Q_RT_x2, Q_R(), trans, x2 ); 00407 SpVectorSlice Q_RT_x2_slc = Q_RT_x2(); 00408 return AbstractLinAlgPack::transVtMtV( 00409 Q_RT_x2_slc, *B_RR_ptr(), no_trans, Q_RT_x2_slc ); 00410 } 00411 else { 00412 SpVector Q_RT_x2; 00413 AbstractLinAlgPack::V_MtV( &Q_RT_x2, Q_R(), trans, x2 ); 00414 SpVector Q_RT_x1; 00415 AbstractLinAlgPack::V_MtV( &Q_RT_x1, Q_R(), trans, x1 ); 00416 return AbstractLinAlgPack::transVtMtV( 00417 Q_RT_x1(), *B_RR_ptr(), no_trans, Q_RT_x2() ); 00418 } 00419 } 00420 } 00421 else if( n_R_ == 0 ) { 00422 // 00423 // B = Q_X *B_XX * Q_X' 00424 // 00425 TEST_FOR_EXCEPT(true); // ToDo: Implement this! 00426 } 00427 else { 00428 // 00429 // B = [ Q_R Q_X ] * [ B_RR op(B_RX) ] * [ Q_R' ] 00430 // [ op(B_RX') B_XX ] [ Q_X' ] 00431 // 00432 // 00433 // a = x1'*B*x2 00434 // => 00435 // a = x1' * [ Q_R Q_X ] * [ B_RR op(B_RX) ] * [ Q_R' ] * x2 00436 // [ op(B_RX') B_XX ] [ Q_X' ] 00437 // 00438 // a = x1'*Q_R*B_RR*Q_R'*x2 + 2*x1'*Q_R*op(B_RX)*Q_X'*x2 + x1'*Q_X*B_XX*Q_X'*x2 00439 // 00440 if( x1.overlap(x2) == DenseLinAlgPack::SAME_MEM ) { 00441 // a = x1'*Q_R*B_RR*Q_R'*x1 + 2*x1'*Q_R*op(B_RX)*Q_X'*x1 + x1'*Q_X*B_XX*Q_X'*x1 00442 SpVector Q_RT_x1; 00443 if( Q_R().nz() ) 00444 AbstractLinAlgPack::V_MtV( &Q_RT_x1, Q_R(), trans, x1 ); 00445 SpVector Q_XT_x1; 00446 if( Q_X().nz() ) 00447 AbstractLinAlgPack::V_MtV( &Q_XT_x1, Q_X(), trans, x1 ); 00448 SpVectorSlice Q_RT_x1_slc = Q_RT_x1(); 00449 SpVectorSlice Q_XT_x1_slc = Q_XT_x1(); 00450 return 00451 ( Q_R().nz() 00452 ? AbstractLinAlgPack::transVtMtV( 00453 Q_RT_x1_slc, *B_RR_ptr(), no_trans, Q_RT_x1_slc ) 00454 : 0.0 00455 ) 00456 + 2*( B_RX_ptr().get() && Q_R().nz() && Q_X().nz() 00457 ? AbstractLinAlgPack::transVtMtV( 00458 Q_RT_x1_slc, *B_RX_ptr(), B_RX_trans(), Q_XT_x1_slc ) 00459 : 0.0 00460 ) 00461 + ( Q_X().nz() 00462 ? AbstractLinAlgPack::transVtMtV( 00463 Q_XT_x1_slc, *B_XX_ptr(), no_trans, Q_XT_x1_slc ) 00464 : 0.0 00465 ); 00466 } 00467 else { 00468 TEST_FOR_EXCEPT(true); // ToDo: Implement this! 00469 } 00470 } 00471 return 0.0; // Will never be executed! 00472 } 00473 00474 // Private 00475 00476 void MatrixHessianSuperBasic::assert_initialized() const 00477 { 00478 if( !n_ ) 00479 throw std::logic_error( 00480 "MatrixHessianSuperBasic::assert_initialized() : Error, " 00481 "The matrix is not initialized yet" ); 00482 } 00483 00484 } // end namespace ConstrainedOptPack 00485 00486 #endif // 0
1.7.4