|
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 #ifndef QPSCHUR_H 00030 #define QPSCHUR_H 00031 00032 #include <ostream> 00033 #include <map> 00034 #include <vector> 00035 00036 #include "ConstrainedOptPack_Types.hpp" 00037 #include "ConstrainedOptPack_MatrixSymAddDelUpdateableWithOpNonsingular.hpp" 00038 #include "AbstractLinAlgPack_GenPermMatrixSlice.hpp" 00039 #include "AbstractLinAlgPack_SpVectorClass.hpp" 00040 #include "AbstractLinAlgPack_MatrixSymOpNonsing.hpp" 00041 #include "AbstractLinAlgPack_MatrixSymOp.hpp" 00042 #include "AbstractLinAlgPack_MatrixOp.hpp" 00043 #include "AbstractLinAlgPack_MatrixSymAddDelUpdateable.hpp" 00044 #include "AbstractLinAlgPack_MatrixOpSerial.hpp" 00045 #include "DenseLinAlgPack_DMatrixClass.hpp" 00046 #include "Teuchos_StandardCompositionMacros.hpp" 00047 #include "Teuchos_StandardMemberCompositionMacros.hpp" 00048 #include "StopWatchPack_stopwatch.hpp" 00049 00050 namespace ConstrainedOptPack { 00051 00052 namespace QPSchurPack { 00053 00055 template < class T > 00056 class vector_one_based_checked : public std::vector<T> 00057 { 00058 typedef vector_one_based_checked this_t; 00059 public: 00061 T& operator()( typename this_t::size_type i ) 00062 { 00063 #ifdef LINALGPACK_CHECK_RANGE 00064 return this->at(i-1); 00065 #else 00066 return this->operator[](i-1); 00067 #endif 00068 } 00070 T operator()( typename this_t::size_type i ) const 00071 { 00072 #ifdef LINALGPACK_CHECK_RANGE 00073 return this->at(i-1); 00074 #else 00075 return this->operator[](i-1); 00076 #endif 00077 } 00078 }; // end class vector_one_based 00079 00080 class Constraints; 00081 class QP; 00082 00153 class QP { 00154 public: 00155 00156 // ///////////////// 00157 // Public Types 00158 00160 typedef vector_one_based_checked<EBounds> x_init_t; 00162 typedef vector_one_based_checked<size_type> l_x_X_map_t; 00164 typedef vector_one_based_checked<size_type> i_x_X_map_t; 00165 00167 typedef QPSchurPack::Constraints Constraints; 00168 00169 // ///////////////// 00170 // Public Interface 00171 00173 virtual ~QP() 00174 {} 00175 00176 // /////////////////////////////////////// 00177 // Initial active set independent members 00178 00180 virtual size_type n() const = 0; 00182 virtual size_type m() const = 0; 00184 virtual const DVectorSlice g() const = 0; 00186 virtual const MatrixSymOp& G() const = 0; 00188 virtual const MatrixOp& A() const = 0; 00189 00190 // ///////////////////////////////////// 00191 // Initial active set specific members 00192 00194 virtual size_type n_R() const = 0; 00195 00206 virtual const x_init_t& x_init() const = 0; 00207 00219 virtual const l_x_X_map_t& l_x_X_map() const = 0; 00220 00230 virtual const i_x_X_map_t& i_x_X_map() const = 0; 00231 00233 /* The bounds of the initially fixed variables. 00234 * 00235 * For 1 <= l <= n_X: 00236 * 00237 \verbatim 00238 / xl(i_x_X_map(l)) : if x_init(i_x_X_map(l)) == LOWER 00239 b_X(l) = | xu(i_x_X_map(l)) : if x_init(i_x_X_map(l)) == UPPER 00240 \ xl(i_x_X_map(l)) = xu(i_x_X_map(l)) : if x_init(i_x_X_map(l)) == EQUALITY 00241 \endverbatim 00242 * 00243 */ 00244 virtual const DVectorSlice b_X() const = 0; 00245 00247 virtual const GenPermMatrixSlice& Q_R() const = 0; 00248 00250 virtual const GenPermMatrixSlice& Q_X() const = 0; 00251 00253 virtual const MatrixSymOpNonsing& Ko() const = 0; 00254 00256 virtual const DVectorSlice fo() const = 0; 00257 00258 // ////////////////////////////////////////////////////////// 00259 // Additional constaints for cl_bar <= A_bar'*x <= cu_bar 00260 00262 virtual Constraints& constraints() = 0; 00263 00265 virtual const Constraints& constraints() const = 0; 00266 00271 virtual void dump_qp( std::ostream& out ); 00272 00273 }; // end class QP 00274 00315 class Constraints { 00316 public: 00317 00319 enum EPickPolicy { ANY_VIOLATED, MOST_VIOLATED }; 00320 00322 virtual ~Constraints() {} 00323 00325 virtual size_type n() const = 0; 00326 00328 virtual size_type m_breve() const = 0; 00329 00331 virtual const MatrixOp& A_bar() const = 0; 00332 00334 virtual void pick_violated_policy( EPickPolicy pick_policy ) = 0; 00336 virtual EPickPolicy pick_violated_policy() const = 0; 00337 00350 virtual void pick_violated( 00351 const DVectorSlice& x, size_type* j_viol, value_type* constr_val 00352 ,value_type* viol_bnd_val, value_type* norm_2_constr, EBounds* bnd, bool* can_ignore 00353 ) const = 0; 00354 00357 virtual void ignore( size_type j ) = 0; 00358 00369 virtual value_type get_bnd( size_type j, EBounds bnd ) const = 0; 00370 00371 }; // end class Constraints 00372 00373 } // end namespace QPSchurPack 00374 00382 class QPSchur { 00383 public: 00384 00387 00389 typedef QPSchurPack::QP QP; 00391 typedef MatrixSymAddDelUpdateable MSADU; 00393 class TestFailed : public std::logic_error 00394 {public: TestFailed(const std::string& what_arg) : std::logic_error(what_arg) {}}; 00396 class InconsistantConstraintsException : public std::logic_error 00397 {public: InconsistantConstraintsException(const std::string& what_arg) : std::logic_error(what_arg) {}}; 00399 class NumericalInstabilityException : public std::runtime_error 00400 {public: NumericalInstabilityException(const std::string& what_arg) : std::runtime_error(what_arg) {}}; 00402 class DualInfeasibleException : public NumericalInstabilityException 00403 {public: DualInfeasibleException(const std::string& what_arg) 00404 : NumericalInstabilityException(what_arg) {}}; 00406 enum ERunTests { RUN_TESTS, NO_TESTS }; 00408 enum ESolveReturn { 00409 OPTIMAL_SOLUTION 00410 ,MAX_ITER_EXCEEDED 00411 ,MAX_RUNTIME_EXEEDED_FAIL 00412 ,MAX_RUNTIME_EXEEDED_DUAL_FEAS 00413 ,MAX_ALLOWED_STORAGE_EXCEEDED 00414 ,INFEASIBLE_CONSTRAINTS 00415 ,NONCONVEX_QP 00416 ,DUAL_INFEASIBILITY 00417 ,SUBOPTIMAL_POINT 00418 }; 00420 enum EOutputLevel { 00421 NO_OUTPUT = 0 00422 ,OUTPUT_BASIC_INFO = 1 00423 ,OUTPUT_ITER_SUMMARY = 2 00424 ,OUTPUT_ITER_STEPS = 3 00425 ,OUTPUT_ACT_SET = 4 00426 ,OUTPUT_ITER_QUANTITIES = 5 00427 }; 00429 static value_type DEGENERATE_MULT; 00430 00432 00435 00437 STANDARD_COMPOSITION_MEMBERS( MatrixSymAddDelUpdateableWithOpNonsingular, schur_comp ); 00438 00441 STANDARD_MEMBER_COMPOSITION_MEMBERS( size_type, max_iter ); 00442 00445 STANDARD_MEMBER_COMPOSITION_MEMBERS( value_type, max_real_runtime ); 00446 00449 STANDARD_MEMBER_COMPOSITION_MEMBERS( value_type, feas_tol ); 00450 00453 STANDARD_MEMBER_COMPOSITION_MEMBERS( value_type, loose_feas_tol ); 00454 00458 STANDARD_MEMBER_COMPOSITION_MEMBERS( value_type, dual_infeas_tol ); 00459 00464 STANDARD_MEMBER_COMPOSITION_MEMBERS( value_type, huge_primal_step ); 00465 00470 STANDARD_MEMBER_COMPOSITION_MEMBERS( value_type, huge_dual_step ); 00471 00474 STANDARD_MEMBER_COMPOSITION_MEMBERS( value_type, warning_tol ); 00475 00478 STANDARD_MEMBER_COMPOSITION_MEMBERS( value_type, error_tol ); 00479 00483 STANDARD_MEMBER_COMPOSITION_MEMBERS( size_type, iter_refine_min_iter ); 00484 00488 STANDARD_MEMBER_COMPOSITION_MEMBERS( size_type, iter_refine_max_iter ); 00489 00493 STANDARD_MEMBER_COMPOSITION_MEMBERS( value_type, iter_refine_opt_tol ); 00494 00498 STANDARD_MEMBER_COMPOSITION_MEMBERS( value_type, iter_refine_feas_tol ); 00499 00503 STANDARD_MEMBER_COMPOSITION_MEMBERS( bool, iter_refine_at_solution ); 00504 00508 STANDARD_MEMBER_COMPOSITION_MEMBERS( bool, salvage_init_schur_comp ); 00509 00512 void pivot_tols( MSADU::PivotTolerances pivot_tols ); 00514 MSADU::PivotTolerances pivot_tols() const; 00515 00517 virtual ~QPSchur() {} 00518 00520 QPSchur( 00521 const schur_comp_ptr_t& schur_comp = Teuchos::null 00522 ,size_type max_iter = 100 00523 ,value_type max_real_runtime = 1e+20 00524 ,value_type feas_tol = 1e-8 00525 ,value_type loose_feas_tol = 1e-6 00526 ,value_type dual_infeas_tol = 1e-12 00527 ,value_type huge_primal_step = 1e+20 00528 ,value_type huge_dual_step = 1e+20 00529 ,value_type warning_tol = 1e-10 00530 ,value_type error_tol = 1e-5 00531 ,size_type iter_refine_min_iter = 1 00532 ,size_type iter_refine_max_iter = 3 00533 ,value_type iter_refine_opt_tol = 1e-12 00534 ,value_type iter_refine_feas_tol = 1e-12 00535 ,bool iter_refine_at_solution = true 00536 ,bool salvage_init_schur_comp = true 00537 ,MSADU::PivotTolerances pivot_tols = MSADU::PivotTolerances( 1e-8,1e-11,1e-11 ) 00538 ); 00539 00598 virtual ESolveReturn solve_qp( 00599 QP& qp 00600 ,size_type num_act_change, const int ij_act_change[], const EBounds bnds[] 00601 ,std::ostream *out, EOutputLevel output_level, ERunTests test_what 00602 ,DVectorSlice* x, SpVector* mu, DVectorSlice* lambda, SpVector* lambda_breve 00603 ,size_type* iter, size_type* num_adds, size_type* num_drops 00604 ); 00605 00607 00615 class U_hat_t : public MatrixOpSerial { 00616 public: 00618 U_hat_t(); 00620 void initialize( 00621 const MatrixSymOp *G 00622 ,const MatrixOp *A 00623 ,const MatrixOp *A_bar 00624 ,const GenPermMatrixSlice *Q_R 00625 ,const GenPermMatrixSlice *P_XF_hat 00626 ,const GenPermMatrixSlice *P_plus_hat 00627 ); 00629 const MatrixSymOp& G() const 00630 { return *G_; } 00632 const MatrixOp* A() const 00633 { return A_; } 00635 const MatrixOp& A_bar() const 00636 { return *A_bar_; } 00638 const GenPermMatrixSlice& Q_R() const 00639 { return *Q_R_; } 00641 const GenPermMatrixSlice& P_XF_hat() const 00642 { return *P_XF_hat_; } 00644 const GenPermMatrixSlice& P_plus_hat() const 00645 { return *P_plus_hat_; } 00646 00648 00649 00651 size_type rows() const; 00653 size_type cols() const; 00654 00656 00659 00661 void Vp_StMtV( 00662 DVectorSlice* vs_lhs, value_type alpha, BLAS_Cpp::Transp trans_rhs1 00663 ,const DVectorSlice& vs_rhs2, value_type beta 00664 ) const; 00666 void Vp_StMtV( 00667 DVectorSlice* vs_lhs, value_type alpha, BLAS_Cpp::Transp trans_rhs1 00668 ,const SpVectorSlice& sv_rhs2, value_type beta 00669 ) const; 00670 00672 00673 private: 00674 const MatrixSymOp *G_; 00675 const MatrixOp *A_; 00676 const MatrixOp *A_bar_; 00677 const GenPermMatrixSlice *Q_R_; 00678 const GenPermMatrixSlice *P_XF_hat_; 00679 const GenPermMatrixSlice *P_plus_hat_; 00680 00681 }; // end class U_hat_t 00682 00714 class ActiveSet { 00715 public: 00716 00717 // ///////////////////// 00718 // Public types 00719 00721 typedef QPSchurPack::QP QP; 00723 typedef MatrixSymAddDelUpdateable MSADU; 00724 00725 // ///////////////////// 00726 // Public interface 00727 00733 STANDARD_COMPOSITION_MEMBERS( MatrixSymAddDelUpdateableWithOpNonsingular, schur_comp ); 00734 00737 STANDARD_MEMBER_COMPOSITION_MEMBERS( MSADU::PivotTolerances, pivot_tols ); 00738 00740 ActiveSet( 00741 const schur_comp_ptr_t &schur_comp 00742 ,MSADU::PivotTolerances pivot_tols = MSADU::PivotTolerances( 1e-6,1e-8,1e-8 ) 00743 ); 00744 00747 00755 void initialize( 00756 QP& qp, size_type num_act_change, const int ij_act_change[] 00757 ,const EBounds bnds[], bool test, bool salvage_init_schur_comp 00758 ,std::ostream *out, EOutputLevel output_level ); 00759 00764 void refactorize_schur_comp(); 00765 00782 bool add_constraint( 00783 size_type ja, EBounds bnd_ja, bool update_steps 00784 ,std::ostream *out, EOutputLevel output_level 00785 ,bool force_refactorization = true 00786 ,bool allow_any_cond = false ); 00787 00795 bool drop_constraint( 00796 int jd, std::ostream *out, EOutputLevel output_level 00797 ,bool force_refactorization = true, bool allow_any_cond = false ); 00798 00806 bool drop_add_constraints( 00807 int jd, size_type ja, EBounds bnd_ja, bool update_steps 00808 ,std::ostream *out, EOutputLevel output_level ); 00809 00811 00814 00816 QP& qp(); 00818 const QP& qp() const; 00819 00821 00824 00829 size_type q_hat() const; 00830 00834 size_type q_plus_hat() const; 00835 00840 size_type q_F_hat() const; 00841 00846 size_type q_C_hat() const; 00847 00852 size_type q_D_hat() const; 00853 00861 int ij_map( size_type s ) const; 00862 00878 size_type s_map( int ij ) const; 00879 00886 value_type constr_norm( size_type s ) const; 00887 00890 EBounds bnd( size_type s ) const; 00891 00897 size_type l_fxfx( size_type k ) const; 00898 00900 const U_hat_t& U_hat() const; 00902 const MatrixSymOpNonsing& S_hat() const; 00904 const GenPermMatrixSlice& P_XF_hat() const; 00906 const GenPermMatrixSlice& P_FC_hat() const; 00908 const GenPermMatrixSlice& P_plus_hat() const; 00910 const GenPermMatrixSlice& Q_XD_hat() const; 00912 const DVectorSlice d_hat() const; 00914 DVectorSlice z_hat(); 00916 const DVectorSlice z_hat() const; 00918 DVectorSlice p_z_hat(); 00920 const DVectorSlice p_z_hat() const; 00922 DVectorSlice mu_D_hat(); 00924 const DVectorSlice mu_D_hat() const; 00926 DVectorSlice p_mu_D_hat(); 00928 const DVectorSlice p_mu_D_hat() const; 00929 00939 bool is_init_fixed( size_type j ) const; 00940 00942 bool all_dof_used_up() const; 00943 00945 00946 private: 00947 00948 // /////////////////////////// 00949 // Private types 00950 00952 typedef std::vector<int> ij_map_t; 00954 typedef std::map<int,size_type> s_map_t; 00956 typedef std::vector<EBounds> bnds_t; 00958 typedef std::vector<int> l_fxfx_t; 00960 typedef std::vector<size_type> P_row_t; 00962 typedef std::vector<size_type> P_col_t; 00963 00964 // /////////////////////////// 00965 // Private data members 00966 00967 bool initialized_; 00968 bool test_; 00969 QP* qp_; // QP being solved. 00970 const QP::x_init_t *x_init_; 00971 size_type n_; 00972 size_type n_R_; 00973 size_type m_; 00974 size_type m_breve_; 00975 size_type q_plus_hat_; 00976 size_type q_F_hat_; 00977 size_type q_C_hat_; 00978 ij_map_t ij_map_; 00979 // s_map_t s_map_; 00980 DVector constr_norm_; 00981 bnds_t bnds_; 00982 l_fxfx_t l_fxfx_; 00983 U_hat_t U_hat_; 00984 // 00985 // for s = 1...q_hat 00986 // 00987 // / e(i) if i > 0 (where: i = -ij_map(s)) 00988 // [P_XF_hat](:,s) = | 00989 // \ 0 otherwise 00990 // 00991 GenPermMatrixSlice P_XF_hat_; // \hat{P}^{XF} \in \Re^{n \times \hat{q}} 00992 P_row_t P_XF_hat_row_; // i 00993 P_row_t P_XF_hat_col_; // s 00994 // 00995 // for s = 1...q_hat 00996 // 00997 // / e(sd) if 0 < j <= n && is_init_fixed(j) 00998 // | (where: j = ij_map(s), sd = s_map(-j)) 00999 // [P_FC_hat](:,s) = | 01000 // \ 0 otherwise 01001 // 01002 GenPermMatrixSlice P_FC_hat_; // {\tilde{P}^{F}}^{T} \hat{P}^{C} \in \Re^{\hat{q} \times \hat{q}} 01003 P_row_t P_FC_hat_row_; // sd 01004 P_row_t P_FC_hat_col_; // s 01005 // 01006 // for s = 1...q_hat 01007 // 01008 // / e(j) if j > 0 && !is_init_fixed(j) (where: j = ij_map(s)) 01009 // [P_plus_hat](:,s) = | 01010 // \ 0 otherwise 01011 // 01012 GenPermMatrixSlice P_plus_hat_; // \hat{P}^{(+)} \in \Re^{n+\breve{m} \times \hat{q}^{D}} 01013 P_row_t P_plus_hat_row_; // j 01014 P_row_t P_plus_hat_col_; // s 01015 // 01016 // for k = 1...q_D_hat 01017 // 01018 // [Q_XD_hat](:,k) = e(i) (where is_init_fixed(i) && s_map(-i) == 0) 01019 // 01020 GenPermMatrixSlice Q_XD_hat_; // \hat{Q}^{XD} \in \Re^{n_X \times \hat{q}^{D}} 01021 P_row_t Q_XD_hat_row_; // i 01022 P_row_t Q_XD_hat_col_; // k 01023 // 01024 DVector d_hat_; // \hat{d} 01025 DVector z_hat_; // \hat{z} 01026 DVector p_z_hat_; 01027 DVector mu_D_hat_; // \hat{\mu}^{D} 01028 DVector p_mu_D_hat_; // p^{\hat{\mu}^{D}} 01029 01030 // /////////////////////////// 01031 // Private member functions 01032 01033 // 01034 void assert_initialized() const; 01035 01036 // Assert in range. 01037 void assert_s( size_type s) const; 01038 01039 // Reinitialize P_XF_hat, P_plus_hat, Q_XD_hat, and U_hat 01040 void reinitialize_matrices(bool test); 01041 01042 // Remove an element from the augmented KKT system. 01043 // This does not update P_plus_hat, P_XF_hat or any 01044 // of the dimensions. Returns true if *out was 01045 // written to. 01046 bool remove_augmented_element( 01047 size_type sd, bool force_refactorization 01048 ,MatrixSymAddDelUpdateable::EEigenValType eigen_val_drop 01049 ,std::ostream *out, EOutputLevel output_level 01050 ,bool allow_any_cond ); 01051 01052 // not defined and not to be called. 01053 ActiveSet(); 01054 01055 }; // end class ActiveSet 01056 01058 const ActiveSet& act_set() const; 01059 01061 static void dump_act_set_quantities( const ActiveSet& act_set, std::ostream& out 01062 , bool print_S_hat = true ); 01063 01064 protected: 01065 01066 // ///////////////////////// 01067 // Protected types 01068 01070 enum EPDSteps { PICK_VIOLATED_CONSTRAINT, UPDATE_ACTIVE_SET, COMPUTE_SEARCH_DIRECTION 01071 , COMPUTE_STEP_LENGTHS, TAKE_STEP }; 01072 01073 // /////////////////////////// 01074 // Protected Member functions 01075 01082 virtual 01083 ESolveReturn qp_algo( 01084 EPDSteps first_step 01085 ,std::ostream *out, EOutputLevel output_level, ERunTests test_what 01086 ,const DVectorSlice& vo, ActiveSet* act_set, DVectorSlice* v 01087 ,DVectorSlice* x, size_type* iter, size_type* num_adds, size_type* num_drops 01088 ,size_type* iter_refine_num_resid, size_type* iter_refine_num_solves 01089 ,StopWatchPack::stopwatch* timer 01090 ); 01091 01094 virtual void set_x( const ActiveSet& act_set, const DVectorSlice& v, DVectorSlice* x ); 01095 01097 virtual void set_multipliers( 01098 const ActiveSet& act_set, const DVectorSlice& v 01099 ,SpVector* mu, DVectorSlice* lambda, SpVector* lambda_breve ); 01100 01102 bool timeout_return( StopWatchPack::stopwatch*timer, std::ostream *out, EOutputLevel output_level ) const; 01103 01105 enum EIterRefineReturn { 01106 ITER_REFINE_NOT_PERFORMED // Did not even perform it (iter_refine_max_iter == 0) 01107 ,ITER_REFINE_ONE_STEP // Only performed one step and the status is not known. 01108 ,ITER_REFINE_NOT_NEEDED // Convergence tolerance was already satisfied 01109 ,ITER_REFINE_IMPROVED // Did not converge but it was improved 01110 ,ITER_REFINE_NOT_IMPROVED // Tried iterative refinement but no improvement 01111 ,ITER_REFINE_CONVERGED // Performed iterative refinement and converged! 01112 }; 01121 EIterRefineReturn iter_refine( 01122 const ActiveSet &act_set 01123 ,std::ostream *out 01124 ,EOutputLevel output_level 01125 ,const value_type ao // Only used if bo != NULL 01126 ,const DVectorSlice *bo // If NULL then assumed to be zero! 01127 ,const value_type aa // Only used if q_hat > 0 01128 ,const DVectorSlice *ba // If NULL then assumed to be zero! Not accessed if q_hat > 0 01129 ,DVectorSlice *v 01130 ,DVectorSlice *z // Can be NULL if q_hat > 0 01131 ,size_type *iter_refine_num_resid 01132 ,size_type *iter_refine_num_solves 01133 ); 01134 01135 private: 01136 01137 // ///////////////////////// 01138 // Private data members 01139 01140 ActiveSet act_set_; // The active set. 01141 01142 }; // end class QPSchur 01143 01144 } // end namespace ConstrainedOptPack 01145 01146 #endif // QPSCHUR_H
1.7.4