|
ConstrainedOptPack: C++ Tools for Constrained (and Unconstrained) Optimization Version of the Day
|
00001 // @HEADER 00002 // *********************************************************************** 00003 // 00004 // Moocho: Multi-functional Object-Oriented arCHitecture for Optimization 00005 // Copyright (2003) Sandia Corporation 00006 // 00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive 00008 // license for use of this work by or on behalf of the U.S. Government. 00009 // 00010 // This library is free software; you can redistribute it and/or modify 00011 // it under the terms of the GNU Lesser General Public License as 00012 // published by the Free Software Foundation; either version 2.1 of the 00013 // License, or (at your option) any later version. 00014 // 00015 // This library is distributed in the hope that it will be useful, but 00016 // WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 // Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public 00021 // License along with this library; if not, write to the Free Software 00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00023 // USA 00024 // Questions? Contact Roscoe A. Bartlett (rabartl@sandia.gov) 00025 // 00026 // *********************************************************************** 00027 // @HEADER 00028 // 00029 // Here we map from the QPSolverRelaxed QP formulation to the LOQO QP formulation. 00030 // 00031 // QPSolverRelaxed QP formulation: 00032 // ------------------------------ 00033 // 00034 // min g'*d + 1/2 * d'*G*d + (eta + 1/2*eta^2) * M 00035 // s.t. dL <= d <= dU 00036 // etaL <= eta 00037 // eL <= op(E)*d - b*eta <= eU 00038 // op(F)*d + (1-eta)*f = 0 00039 // 00040 // LOQO QP formulation: 00041 // ------------------- 00042 // 00043 // min c'*x + 1/2 * x'*Q*x 00044 // s.t. b <= A*x <= b + r 00045 // l <= x <= u 00046 // 00047 // Mapping => 00048 // 00049 // LOQO QPSolverRelaxed 00050 // ---- --------------- 00051 // x [ d; eta ] 00052 // c [ g; M ] 00053 // Q [ G, 0; 0, M ] 00054 // A [ op(E), -b; op(F), -f ] 00055 // b [ eL; -f ] 00056 // r [ eU-eL; 0 ] 00057 // l [ dL, etaL ] 00058 // u [ dU, +inf ] 00059 // 00060 // Above, in the LOQO formulation all singly bounded inequalities 00061 // must be formulated as b(j) <= A(j,:)*x with r(j) = inf. This 00062 // will require some fudging since eL(j) == -inf may be true in some 00063 // cases. Here we will have to exchange eL(j) and eU(j) and use 00064 // A(j,:) = -op(E)(j,:). 00065 // 00066 00067 #ifdef CONSTRAINED_OPTIMIZATION_PACK_USE_LOQO 00068 00069 #include <assert.h> 00070 00071 #include <vector> 00072 00073 #include "ConstrainedOptPack_QPSolverRelaxedLOQO.hpp" 00074 #include "ConstrainedOptPack/src/AbstractLinAlgPack_MatrixExtractInvCholFactor.hpp" 00075 #include "AbstractLinAlgPack_SpVectorOp.hpp" 00076 #include "AbstractLinAlgPack/src/AbstractLinAlgPack_MatrixOp.hpp" 00077 #include "AbstractLinAlgPack_SortByDescendingAbsValue.hpp" 00078 #include "AbstractLinAlgPack_sparse_bounds.hpp" 00079 #include "AbstractLinAlgPack/src/AbstractLinAlgPack_EtaVector.hpp" 00080 #include "AbstractLinAlgPack_sparse_bounds.hpp" 00081 #include "DenseLinAlgPack_LinAlgOpPack.hpp" 00082 #include "Midynamic_cast_verbose.h" 00083 #include "MiWorkspacePack.h" 00084 00085 extern "C" { 00086 #include "loqo.h" // -I$(LOQODIR) 00087 #include "myalloc.h" // -I$(LOQODIR) 00088 } // end extern "C" 00089 00090 namespace LinAlgOpPack { 00091 using AbstractLinAlgPack::Vp_StV; 00092 using AbstractLinAlgPack::Mp_StM; 00093 using AbstractLinAlgPack::Vp_StMtV; 00094 } 00095 00096 namespace ConstrainedOptPack { 00097 00098 // /////////////////////////////////////// 00099 // Members for QPSolverRelaxedLOQO::InitLOQOHessianJacobian 00100 00101 void QPSolverRelaxedLOQO::InitLOQOHessianJacobian::init_hess_jacob( 00102 const MatrixOp& G, const value_type bigM 00103 , const MatrixOp* E, BLAS_Cpp::Transp trans_E, const DVectorSlice* b 00104 , const int loqo_b_stat[], const size_type num_inequal 00105 , const MatrixOp* F, BLAS_Cpp::Transp trans_F, const DVectorSlice* f 00106 , void* _loqo_lp 00107 ) const 00108 { 00109 00110 LOQO* loqo_lp = (LOQO*)_loqo_lp; 00111 00112 const size_type 00113 nd = G.rows(), 00114 m_in = E ? b->size() : 0, 00115 m_eq = F ? f->size() : 0; 00116 00117 TEST_FOR_EXCEPT( !( loqo_lp->n == nd + 1 ) ); 00118 TEST_FOR_EXCEPT( !( loqo_lp->m == num_inequal + m_eq ) ); 00119 00120 // This default implementation assumes G, E and F are completely dense! 00121 00122 // 00123 // Setup Q 00124 // 00125 00126 loqo_lp->qnz = nd*nd + 1; 00127 MALLOC( loqo_lp->Q, loqo_lp->qnz, double ); 00128 MALLOC( loqo_lp->iQ, loqo_lp->qnz, int ); 00129 MALLOC( loqo_lp->kQ, nd+2, int ); 00130 // Setup kQ[] and iQ[] 00131 {for( size_type j = 1; j <= nd; ++j ) { 00132 loqo_lp->kQ[j-1] = nd*(j-1); 00133 for( size_type i = 1; i <= nd; ++i ) 00134 loqo_lp->iQ[ loqo_lp->kQ[j-1] + (i-1) ] = i-1; // zero based in LOQO 00135 }} 00136 loqo_lp->kQ[nd] = nd*nd; 00137 loqo_lp->iQ[loqo_lp->kQ[nd]] = nd; // zero based in LOQO 00138 loqo_lp->kQ[nd+1] = nd*nd + 1; 00139 // Setup Q[] 00140 { 00141 DMatrixSlice Q( loqo_lp->Q, nd*nd, nd, nd, nd ); 00142 LinAlgOpPack::assign( &Q, G, BLAS_Cpp::no_trans ); 00143 loqo_lp->Q[nd*nd] = bigM; 00144 } 00145 00146 // 00147 // Setup A 00148 // 00149 00150 loqo_lp->nz = (num_inequal+m_eq) * (nd+1); 00151 MALLOC( loqo_lp->A, loqo_lp->nz, double ); 00152 MALLOC( loqo_lp->iA, loqo_lp->nz, int ); 00153 MALLOC( loqo_lp->kA, nd+2, int ); 00154 00155 if( num_inequal == m_in ) { 00156 // All the inequalities have finite bounds 00157 // Setup kA[] and iA[] 00158 {for( size_type j = 1; j <= nd+1; ++j ) { 00159 loqo_lp->kA[j-1] = (m_in+m_eq)*(j-1); 00160 for( size_type i = 1; i <= m_in+m_eq; ++i ) 00161 loqo_lp->iA[ loqo_lp->kA[j-1] + (i-1) ] = i-1; // zero based in LOQO 00162 }} 00163 loqo_lp->kA[nd+1] = (m_in+m_eq)*(nd+1); 00164 // Setup A[] 00165 DMatrixSlice A( loqo_lp->A, loqo_lp->nz, loqo_lp->m, loqo_lp->m, nd+1 ); 00166 if(E) { 00167 LinAlgOpPack::assign( &A(1,m_in,1,nd), *E, trans_E ); // A(1:m_in,1:nd) = op(E) 00168 LinAlgOpPack::V_StV( &A.col(nd+1)(1,m_in), -1.0, *b ); // A(1:m_in,nd+1) = -b 00169 } 00170 if(F) { 00171 LinAlgOpPack::assign( &A(m_in+1,m_in+m_eq,1,nd), *F, trans_F ); // A(m_in+1:m_in+m_eq,1:nd) = op(F) 00172 LinAlgOpPack::V_StV( &A.col(nd+1)(m_in+1,m_in+m_eq), -1.0, *f ); // A(m_in+1:m_in+m_eq,nd+1) = -f 00173 } 00174 } 00175 else { 00176 // At least one of the inequality constriants has 00177 // both infinite upper and lower bounds. 00178 TEST_FOR_EXCEPT(true); // ToDo: Finish this! 00179 } 00180 00181 // Loop through and adjust A for absent lower bound and using upper bound 00182 if( num_inequal ) { 00183 DMatrixSlice A( loqo_lp->A, loqo_lp->nz, loqo_lp->m, loqo_lp->m, nd+1 ); 00184 for(size_type k = 1; k <= num_inequal; ++k ) { 00185 const int j = loqo_b_stat[k-1]; 00186 if( j < 0 ) 00187 DenseLinAlgPack::Vt_S( &A.row(j), -1.0 ); 00188 } 00189 } 00190 00191 } 00192 00193 // /////////////////////////////////////// 00194 // Members for QPSolverRelaxedLOQO 00195 00196 QPSolverRelaxedLOQO::QPSolverRelaxedLOQO( 00197 const init_hess_jacob_ptr_t init_hess_jacob 00198 ,value_type bigM 00199 ,value_type nonbinding_lag_mult 00200 ) 00201 :init_hess_jacob_(init_hess_jacob) 00202 ,bigM_(bigM) 00203 ,nonbinding_lag_mult_(nonbinding_lag_mult) 00204 { 00205 // bigM_ = 1.0; // Just test this! 00206 nonbinding_lag_mult_ = 1e-6; 00207 } 00208 00209 QPSolverRelaxedLOQO::~QPSolverRelaxedLOQO() 00210 { 00211 this->release_memory(); 00212 } 00213 00214 // Overridden from QPSolverRelaxed 00215 00216 QPSolverStats 00217 QPSolverRelaxedLOQO::get_qp_stats() const 00218 { 00219 return qp_stats_; 00220 } 00221 00222 void QPSolverRelaxedLOQO::release_memory() 00223 { 00224 // Todo: resize to zero all the workspace! 00225 } 00226 00227 QPSolverStats::ESolutionType 00228 QPSolverRelaxedLOQO::imp_solve_qp( 00229 std::ostream* out, EOutputLevel olevel, ERunTests test_what 00230 , const DVectorSlice& g, const MatrixOp& G 00231 , value_type etaL 00232 , const SpVectorSlice& dL, const SpVectorSlice& dU 00233 , const MatrixOp* E, BLAS_Cpp::Transp trans_E, const DVectorSlice* b 00234 , const SpVectorSlice* eL, const SpVectorSlice* eU 00235 , const MatrixOp* F, BLAS_Cpp::Transp trans_F, const DVectorSlice* f 00236 , value_type* obj_d 00237 , value_type* eta, DVectorSlice* d 00238 , SpVector* nu 00239 , SpVector* mu, DVectorSlice* Ed 00240 , DVectorSlice* lambda, DVectorSlice* Fd 00241 ) 00242 { 00243 using Teuchos::Workspace; 00244 Teuchos::WorkspaceStore* wss = wsp::default_workspace_store.get(); 00245 00246 const value_type inf_bnd = std::numeric_limits<value_type>::max(); 00247 // const value_type real_big = 1e+20; 00248 const value_type real_big = HUGE_VAL; 00249 00250 const size_type 00251 nd = g.size(), 00252 m_in = E ? b->size() : 0, 00253 m_eq = F ? f->size() : 0; 00254 00255 // 00256 // Create a LOQO QP definition struct 00257 // 00258 00259 LOQO *loqo_lp = openlp(); 00260 TEST_FOR_EXCEPT( !( loqo_lp ) ); 00261 00262 // 00263 // Setup loqo_r and loqo_b and count the number of actual 00264 // constraints. 00265 // 00266 00267 // LOQO's b vector storage 00268 MALLOC( loqo_lp->b, m_in+m_eq, double ); // May not use all of this storage 00269 DVectorSlice loqo_b( loqo_lp->b, m_in+m_eq ); 00270 // LOQO's r vector storage 00271 MALLOC( loqo_lp->r, m_in+m_eq, double ); // May not use all of this storage 00272 DVectorSlice loqo_r( loqo_lp->r, m_in+m_eq ); 00273 // Gives status of b. 00274 // / j : if eL(j) > -inf_bnd 00275 // loqo_b_stat(k) = | 00276 // \ -j : if eL(j) <= -inf_bnd && eU(j) < +inf_bnd 00277 // 00278 // , for k = 1...num_inequal 00279 // 00280 Workspace<int> loqo_b_stat_ws(wss,m_in); // May not use all of this 00281 DenseLinAlgPack::VectorSliceTmpl<int> loqo_b_stat(&loqo_b_stat_ws[0],loqo_b_stat_ws.size()); 00282 std::fill( loqo_b_stat.begin(), loqo_b_stat.end(), 0 ); // Initialize to zero 00283 00284 // Fill up loqo_b, loqo_r and loqo_b_stat 00285 size_type num_inequal = 0; // The actual number of bouned general inequalities 00286 if(E) { 00287 // Read iterators 00288 AbstractLinAlgPack::sparse_bounds_itr 00289 eLU_itr( eL->begin(), eL->end(), eL->offset() 00290 , eU->begin(), eU->end(), eU->offset(), inf_bnd ); 00291 // written iterators 00292 DVectorSlice::iterator 00293 b_itr = loqo_b.begin(), 00294 r_itr = loqo_r.begin(); 00295 DenseLinAlgPack::VectorSliceTmpl<int>::iterator 00296 b_stat_itr = loqo_b_stat.begin(); 00297 // loop 00298 for( int k = 1; !eLU_itr.at_end(); ++k, ++eLU_itr, ++b_itr, ++r_itr, ++b_stat_itr, ++num_inequal ) 00299 { 00300 const size_type j = eLU_itr.indice(); 00301 if(eLU_itr.lbound() > -inf_bnd) { 00302 *b_itr = eLU_itr.lbound(); 00303 *r_itr = eLU_itr.ubound() >= inf_bnd ? real_big : eLU_itr.ubound() - eLU_itr.lbound(); 00304 *b_stat_itr = j; // We need to make A(k,:) = [ +op(E)(j,:), -b(j) ] 00305 } 00306 else { 00307 TEST_FOR_EXCEPT( !( eLU_itr.ubound() < +inf_bnd ) ); 00308 *b_itr = -eLU_itr.ubound(); 00309 *r_itr = eLU_itr.lbound() <= -inf_bnd ? real_big : - eLU_itr.lbound() + eLU_itr.ubound(); 00310 *b_stat_itr = -j; // We need to make A(k,:) = [ -op(E)(j,:), +b(j) ] 00311 } 00312 } 00313 } 00314 if(F) { 00315 LinAlgOpPack::V_StV( &loqo_b(num_inequal+1,num_inequal+m_eq), -1.0, *f ); 00316 loqo_r(num_inequal+1,num_inequal+m_eq) = 0.0; 00317 } 00318 00319 // 00320 // Setup the QP dimensions 00321 // 00322 00323 loqo_lp->n = nd+1; 00324 loqo_lp->m = num_inequal + m_eq; 00325 00326 // 00327 // Setup loqo_c, loqo_l and loqo_u 00328 // 00329 00330 // LOQO's c vector storage 00331 MALLOC( loqo_lp->c, nd+1, double ); 00332 DVectorSlice loqo_c( loqo_lp->c, nd+1 ); 00333 loqo_c(1,nd) = g; 00334 loqo_c(nd+1) = bigM(); 00335 00336 // LOQO's l vector storage 00337 MALLOC( loqo_lp->l, nd+1, double ); 00338 DVectorSlice loqo_l( loqo_lp->l, nd+1 ); 00339 std::fill( loqo_l.begin(), loqo_l.end(), -real_big ); 00340 { 00341 SpVectorSlice::const_iterator 00342 dL_itr = dL.begin(), 00343 dL_end = dL.end(); 00344 for( ; dL_itr != dL_end; ++dL_itr ) 00345 loqo_l( dL_itr->indice() + dL.offset() ) = dL_itr->value(); 00346 } 00347 loqo_l(nd+1) = etaL; 00348 00349 // LOQO's u vector storage 00350 MALLOC( loqo_lp->u, nd+1, double ); 00351 DVectorSlice loqo_u( loqo_lp->u, nd+1 ); 00352 std::fill( loqo_u.begin(), loqo_u.end(), +real_big ); 00353 { 00354 SpVectorSlice::const_iterator 00355 dU_itr = dU.begin(), 00356 dU_end = dU.end(); 00357 for( ; dU_itr != dU_end; ++dU_itr ) 00358 loqo_u( dU_itr->indice() + dU.offset() ) = dU_itr->value(); 00359 } 00360 loqo_u(nd+1) = +real_big; 00361 00362 // 00363 // Setup the objective and constraint matrices (using strategy interface). 00364 // 00365 00366 init_hess_jacob().init_hess_jacob( 00367 G,bigM(),E,trans_E,b,&loqo_b_stat[0],num_inequal,F,trans_F,f 00368 ,loqo_lp); 00369 00370 // 00371 // Setup the starting point 00372 // 00373 00374 MALLOC( loqo_lp->x, nd+1, double ); 00375 DVectorSlice loqo_x( loqo_lp->x, nd+1 ); 00376 loqo_x(1,nd) = *d; 00377 loqo_x(nd+1) = *eta; 00378 00379 // 00380 // Set some control parameters 00381 // 00382 00383 // strcpy( loqo_lp->name, "loqo_qp" ); 00384 loqo_lp->quadratic = 1; 00385 loqo_lp->convex = 1; 00386 switch( olevel ) { 00387 case PRINT_NONE: 00388 loqo_lp->verbose = 0; 00389 break; 00390 case PRINT_BASIC_INFO: 00391 loqo_lp->verbose = 1; 00392 break; 00393 case PRINT_ITER_SUMMARY: 00394 loqo_lp->verbose = 2; 00395 break; 00396 case PRINT_ITER_STEPS: 00397 loqo_lp->verbose = 3; 00398 break; 00399 case PRINT_ITER_ACT_SET: 00400 loqo_lp->verbose = 4; 00401 break; 00402 case PRINT_ITER_VECTORS: 00403 loqo_lp->verbose = 5; 00404 break; 00405 case PRINT_EVERY_THING: 00406 loqo_lp->verbose = 6; 00407 break; 00408 default: 00409 TEST_FOR_EXCEPT(true); 00410 } 00411 00412 // 00413 // Solve the QP 00414 // 00415 00416 if( out && olevel >= PRINT_BASIC_INFO ) { 00417 *out << "\nSolving QP using LOQO ...\n"; 00418 out->flush(); 00419 } 00420 00421 const int loqo_status = solvelp(loqo_lp); 00422 00423 if( out && olevel >= PRINT_BASIC_INFO ) { 00424 *out << "\nLOQO returned status = " << loqo_status << "\n"; 00425 } 00426 00427 // 00428 // Map the solution to the output arguments 00429 // 00430 00431 TEST_FOR_EXCEPT( !( loqo_lp->x ) ); 00432 DVectorSlice loqo_x_sol( loqo_lp->x, nd+1 ); 00433 00434 // d 00435 *d = loqo_x_sol(1,nd); 00436 00437 // eta 00438 *eta = loqo_x_sol(nd+1); 00439 00440 // obj_d 00441 if(obj_d) 00442 *obj_d = loqo_lp->primal_obj - (*eta + 0.5 * (*eta)*(*eta)) * bigM(); 00443 00444 // nu 00445 if(nu) { 00446 nu->resize(nd,nd); 00447 TEST_FOR_EXCEPT( !( loqo_lp->z ) ); 00448 TEST_FOR_EXCEPT( !( loqo_lp->s ) ); 00449 const DVectorSlice 00450 loqo_z(loqo_lp->z,loqo_lp->n), // Multipliers for l - x <= 0 00451 loqo_s(loqo_lp->s,loqo_lp->n); // Multipliers for x - u <= 0 00452 DVectorSlice::const_iterator 00453 z_itr = loqo_z.begin(), 00454 s_itr = loqo_s.begin(); 00455 typedef SpVector::element_type ele_t; 00456 for( size_type i = 1; i <= nd; ++i, ++z_itr, ++s_itr ) { 00457 if( *z_itr > *s_itr && *z_itr >= nonbinding_lag_mult() ) { 00458 // Lower bound is active 00459 nu->add_element(ele_t(i,-(*z_itr))); 00460 } 00461 else if( *s_itr > *z_itr && *s_itr >= nonbinding_lag_mult() ) { 00462 // Upper bound is active 00463 nu->add_element(ele_t(i,+(*s_itr))); 00464 } 00465 } 00466 // We could look at z(nd+1) and s(nd+1) for the value of kappa? 00467 nu->assume_sorted(true); 00468 } 00469 00470 // mu 00471 if(mu) { 00472 mu->resize(m_in,num_inequal); 00473 DenseLinAlgPack::VectorSliceTmpl<int>::iterator 00474 b_stat_itr = loqo_b_stat.begin(); 00475 TEST_FOR_EXCEPT( !( loqo_lp->v ) ); 00476 TEST_FOR_EXCEPT( !( loqo_lp->q ) ); 00477 const DVectorSlice 00478 loqo_v(loqo_lp->v,loqo_lp->m), // Multipliers for b <= A*x 00479 loqo_q(loqo_lp->q,loqo_lp->m); // Multipliers for A*x <= b + r 00480 DVectorSlice::const_iterator 00481 v_itr = loqo_v.begin(), 00482 q_itr = loqo_q.begin(); 00483 // loop 00484 typedef SpVector::element_type ele_t; 00485 for( size_type k = 1; k <= num_inequal; ++k, ++b_stat_itr, ++v_itr, ++q_itr ) { 00486 const int j = *b_stat_itr; 00487 if( *v_itr > *q_itr && *v_itr >= nonbinding_lag_mult() ) { 00488 // Lower bound is active 00489 if( j < 0 ) // We had to flip this since it was really and upper bound 00490 mu->add_element(ele_t(-j,+(*v_itr))); 00491 else // This really was a lower bound 00492 mu->add_element(ele_t(+j,-(*v_itr))); 00493 } 00494 else if( *q_itr > *v_itr && *q_itr >= nonbinding_lag_mult() ) { 00495 // Upper bound is active 00496 mu->add_element(ele_t(+j,+(*q_itr))); 00497 } 00498 } 00499 } 00500 00501 // Ed 00502 if(Ed) { 00503 LinAlgOpPack::V_MtV( Ed, *E, trans_E, *d ); 00504 } 00505 00506 // lambda 00507 if(lambda) { 00508 TEST_FOR_EXCEPT( !( loqo_lp->y ) ); 00509 const DVectorSlice 00510 loqo_y(loqo_lp->y,loqo_lp->m); // Multipliers for equalities 00511 DVectorSlice::const_iterator 00512 y_itr = loqo_y.begin() + num_inequal; // Get iterators to equalities 00513 DVectorSlice::iterator 00514 lambda_itr = lambda->begin(); 00515 // loop 00516 for( size_type k = 1; k <= m_eq; ++k, ++y_itr, ++lambda_itr ) { 00517 *lambda_itr = -(*y_itr); 00518 } 00519 } 00520 00521 // Fd 00522 if(Fd) { 00523 LinAlgOpPack::V_MtV( Fd, *F, trans_F, *d ); 00524 } 00525 00526 // 00527 // Setup the QP statistics 00528 // 00529 00530 QPSolverStats::ESolutionType solution_type = QPSolverStats::OPTIMAL_SOLUTION; // Assume this? 00531 switch( loqo_status ) { // I had to find this out by trial and error! 00532 case 0: 00533 solution_type = QPSolverStats::OPTIMAL_SOLUTION; 00534 break; 00535 case 2: 00536 solution_type = QPSolverStats::DUAL_FEASIBLE_POINT; 00537 break; 00538 default: 00539 TEST_FOR_EXCEPT(true); 00540 } 00541 00542 qp_stats_.set_stats( 00543 solution_type, QPSolverStats::CONVEX 00544 ,loqo_lp->iter, QPSolverStats::NOT_KNOWN, QPSolverStats::NOT_KNOWN 00545 ,false, *eta > 0.0 ); 00546 00547 // 00548 // Clean up dynamically allocated memory for LOQO 00549 // 00550 00551 inv_clo(); // frees memory associated with matrix factorization 00552 closelp(loqo_lp); // frees all allocated arrays with free(...). 00553 00554 return qp_stats_.solution_type(); 00555 00556 } 00557 00558 } // end namespace ConstrainedOptPack 00559 00560 #endif // CONSTRAINED_OPTIMIZATION_PACK_USE_LOQO
1.7.4