/* * This file is part of qpOASES. * * qpOASES -- An Implementation of the Online Active Set Strategy. * Copyright (C) 2007-2008 by Hans Joachim Ferreau et al. All rights reserved. * * qpOASES is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * qpOASES is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with qpOASES; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ /** * \file SRC/QProblemB.cpp * \author Hans Joachim Ferreau * \version 1.3embedded * \date 2007-2008 * * Implementation of the QProblemB class which is able to use the newly * developed online active set strategy for parametric quadratic programming. */ #include #include void printmatrix(char *name, double *A, int m, int n) { int i, j; printf("%s = [...\n", name); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) printf(" % 9.4f", A[i*n+j]); printf(",\n"); } printf("];\n"); } /***************************************************************************** * P U B L I C * *****************************************************************************/ /* * Q P r o b l e m B */ QProblemB::QProblemB( ) { /* reset global message handler */ getGlobalMessageHandler( )->reset( ); hasHessian = BT_FALSE; bounds.init( 0 ); hasCholesky = BT_FALSE; tau = 0.0; hessianType = HST_POSDEF_NULLSPACE; /* Hessian is assumed to be positive definite by default */ infeasible = BT_FALSE; unbounded = BT_FALSE; status = QPS_NOTINITIALISED; #ifdef PC_DEBUG printlevel = PL_MEDIUM; setPrintLevel( PL_MEDIUM ); #else printlevel = QPOASES_PRINTLEVEL; #endif count = 0; } /* * Q P r o b l e m B */ QProblemB::QProblemB( int _nV ) { /* consistency check */ if ( _nV <= 0 ) { _nV = 1; THROWERROR( RET_INVALID_ARGUMENTS ); } hasHessian = BT_FALSE; /* reset global message handler */ getGlobalMessageHandler( )->reset( ); bounds.init( _nV ); hasCholesky = BT_FALSE; tau = 0.0; hessianType = HST_POSDEF_NULLSPACE; /* Hessian is assumed to be positive definite by default */ infeasible = BT_FALSE; unbounded = BT_FALSE; status = QPS_NOTINITIALISED; #ifdef PC_DEBUG printlevel = PL_MEDIUM; setPrintLevel( PL_MEDIUM ); #else printlevel = QPOASES_PRINTLEVEL; #endif count = 0; } /* * Q P r o b l e m B */ QProblemB::QProblemB( const QProblemB& rhs ) { int i, j; int _nV = rhs.bounds.getNV( ); for( i=0; i<_nV; ++i ) for( j=0; j<_nV; ++j ) H[i*NVMAX + j] = rhs.H[i*NVMAX + j]; hasHessian = rhs.hasHessian; for( i=0; i<_nV; ++i ) g[i] = rhs.g[i]; for( i=0; i<_nV; ++i ) lb[i] = rhs.lb[i]; for( i=0; i<_nV; ++i ) ub[i] = rhs.ub[i]; bounds = rhs.bounds; for( i=0; i<_nV; ++i ) for( j=0; j<_nV; ++j ) R[i*NVMAX + j] = rhs.R[i*NVMAX + j]; hasCholesky = rhs.hasCholesky; for( i=0; i<_nV; ++i ) x[i] = rhs.x[i]; for( i=0; i<_nV; ++i ) y[i] = rhs.y[i]; tau = rhs.tau; hessianType = rhs.hessianType; infeasible = rhs.infeasible; unbounded = rhs.unbounded; status = rhs.status; printlevel = rhs.printlevel; count = rhs.count; } /* * ~ Q P r o b l e m B */ QProblemB::~QProblemB( ) { } /* * o p e r a t o r = */ QProblemB& QProblemB::operator=( const QProblemB& rhs ) { int i, j; if ( this != &rhs ) { int _nV = rhs.bounds.getNV( ); for( i=0; i<_nV; ++i ) for( j=0; j<_nV; ++j ) H[i*NVMAX + j] = rhs.H[i*NVMAX + j]; hasHessian = rhs.hasHessian; for( i=0; i<_nV; ++i ) g[i] = rhs.g[i]; for( i=0; i<_nV; ++i ) lb[i] = rhs.lb[i]; for( i=0; i<_nV; ++i ) ub[i] = rhs.ub[i]; bounds = rhs.bounds; for( i=0; i<_nV; ++i ) for( j=0; j<_nV; ++j ) R[i*NVMAX + j] = rhs.R[i*NVMAX + j]; hasCholesky = rhs.hasCholesky; for( i=0; i<_nV; ++i ) x[i] = rhs.x[i]; for( i=0; i<_nV; ++i ) y[i] = rhs.y[i]; tau = rhs.tau; hessianType = rhs.hessianType; infeasible = rhs.infeasible; unbounded = rhs.unbounded; status = rhs.status; printlevel = rhs.printlevel; setPrintLevel( rhs.printlevel ); count = rhs.count; } return *this; } /* * r e s e t */ returnValue QProblemB::reset( ) { int i, j; int nV = getNV( ); /** 0) Reset has Hessian flag. */ hasHessian = BT_FALSE; /* 1) Reset bounds. */ bounds.init( nV ); /* 2) Reset Cholesky decomposition. */ for( i=0; ithrowInfo( RET_ITERATION_STARTED,messageString,__FUNCTION__,__FILE__,__LINE__,VS_VISIBLE ); #endif } /* 1) Setup index arrays. */ if ( bounds.getFree( )->getNumberArray( FR_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_HOTSTART_FAILED ); if ( bounds.getFixed( )->getNumberArray( FX_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_HOTSTART_FAILED ); /* 2) Initialize shift direction of the gradient and the bounds. */ returnvalue = hotstart_determineDataShift( FX_idx, g_new,lb_new,ub_new, delta_g,delta_lb,delta_ub, Delta_bB_isZero ); if ( returnvalue != SUCCESSFUL_RETURN ) { nWSR = l; THROWERROR( RET_SHIFT_DETERMINATION_FAILED ); return returnvalue; } /* 3) Determination of step direction of X and Y. */ returnvalue = hotstart_determineStepDirection( FR_idx,FX_idx, delta_g,delta_lb,delta_ub, Delta_bB_isZero, delta_xFX,delta_xFR,delta_yFX ); if ( returnvalue != SUCCESSFUL_RETURN ) { nWSR = l; THROWERROR( RET_STEPDIRECTION_DETERMINATION_FAILED ); return returnvalue; } /* 4) Determination of step length TAU. */ returnvalue = hotstart_determineStepLength( FR_idx,FX_idx, delta_lb,delta_ub, delta_xFR,delta_yFX, BC_idx,BC_status ); if ( returnvalue != SUCCESSFUL_RETURN ) { nWSR = l; THROWERROR( RET_STEPLENGTH_DETERMINATION_FAILED ); return returnvalue; } /* 5) Realization of the homotopy step. */ returnvalue = hotstart_performStep( FR_idx,FX_idx, delta_g,delta_lb,delta_ub, delta_xFX,delta_xFR,delta_yFX, BC_idx,BC_status ); if ( returnvalue != SUCCESSFUL_RETURN ) { nWSR = l; /* stop runtime measurement */ if ( cputime != 0 ) *cputime = getCPUtime( ) - starttime; /* optimal solution found? */ if ( returnvalue == RET_OPTIMAL_SOLUTION_FOUND ) { status = QPS_SOLVED; if ( printlevel == PL_HIGH ) THROWINFO( RET_OPTIMAL_SOLUTION_FOUND ); #ifdef PC_DEBUG if ( printIteration( l,BC_idx,BC_status ) != SUCCESSFUL_RETURN ) THROWERROR( RET_PRINT_ITERATION_FAILED ); /* do not pass this as return value! */ #endif /* check KKT optimality conditions */ return checkKKTconditions( ); } else { /* checks for infeasibility... */ if ( infeasible == BT_TRUE ) { status = QPS_HOMOTOPYQPSOLVED; return THROWERROR( RET_HOTSTART_STOPPED_INFEASIBILITY ); } /* ...unboundedness... */ if ( unbounded == BT_TRUE ) /* not necessary since objective function convex! */ return THROWERROR( RET_HOTSTART_STOPPED_UNBOUNDEDNESS ); /* ... and throw unspecific error otherwise */ THROWERROR( RET_HOMOTOPY_STEP_FAILED ); return returnvalue; } } /* 6) Output information of successful QP iteration. */ status = QPS_HOMOTOPYQPSOLVED; #ifdef PC_DEBUG if ( printIteration( l,BC_idx,BC_status ) != SUCCESSFUL_RETURN ) THROWERROR( RET_PRINT_ITERATION_FAILED ); /* do not pass this as return value! */ #endif } /* stop runtime measurement */ if ( cputime != 0 ) *cputime = getCPUtime( ) - starttime; /* if programm gets to here, output information that QP could not be solved * within the given maximum numbers of working set changes */ if ( printlevel == PL_HIGH ) { #ifdef PC_DEBUG sprintf( messageString,"(nWSR = %d)",nWSR ); return getGlobalMessageHandler( )->throwWarning( RET_MAX_NWSR_REACHED,messageString,__FUNCTION__,__FILE__,__LINE__,VS_VISIBLE ); #endif } /* Finally check KKT optimality conditions. */ returnValue returnvalueKKTcheck = checkKKTconditions( ); if ( returnvalueKKTcheck != SUCCESSFUL_RETURN ) return returnvalueKKTcheck; else return RET_MAX_NWSR_REACHED; } /* * g e t N Z */ int QProblemB::getNZ( ) { /* if no constraints are present: nZ=nFR */ return bounds.getFree( )->getLength( ); } /* * g e t O b j V a l */ real_t QProblemB::getObjVal( ) const { real_t objVal; /* calculated optimal objective function value * only if current QP has been solved */ if ( ( getStatus( ) == QPS_AUXILIARYQPSOLVED ) || ( getStatus( ) == QPS_HOMOTOPYQPSOLVED ) || ( getStatus( ) == QPS_SOLVED ) ) { objVal = getObjVal( x ); } else { objVal = INFTY; } return objVal; } /* * g e t O b j V a l */ real_t QProblemB::getObjVal( const real_t* const _x ) const { int i, j; int nV = getNV( ); real_t obj_tmp = 0.0; for( i=0; i= PL_MEDIUM ) && ( printlevel != _printlevel ) ) THROWINFO( RET_PRINTLEVEL_CHANGED ); #endif printlevel = _printlevel; /* update message handler preferences */ switch ( printlevel ) { case PL_NONE: getGlobalMessageHandler( )->setErrorVisibilityStatus( VS_HIDDEN ); getGlobalMessageHandler( )->setWarningVisibilityStatus( VS_HIDDEN ); getGlobalMessageHandler( )->setInfoVisibilityStatus( VS_HIDDEN ); break; case PL_LOW: getGlobalMessageHandler( )->setErrorVisibilityStatus( VS_VISIBLE ); getGlobalMessageHandler( )->setWarningVisibilityStatus( VS_HIDDEN ); getGlobalMessageHandler( )->setInfoVisibilityStatus( VS_HIDDEN ); break; default: /* PL_MEDIUM, PL_HIGH */ getGlobalMessageHandler( )->setErrorVisibilityStatus( VS_VISIBLE ); getGlobalMessageHandler( )->setWarningVisibilityStatus( VS_VISIBLE ); getGlobalMessageHandler( )->setInfoVisibilityStatus( VS_VISIBLE ); break; } return SUCCESSFUL_RETURN; } /***************************************************************************** * P R O T E C T E D * *****************************************************************************/ /* * c h e c k F o r I d e n t i t y H e s s i a n */ returnValue QProblemB::checkForIdentityHessian( ) { int i, j; int nV = getNV( ); /* nothing to do as status flag remains unaltered * if Hessian differs from identity matrix */ if ( hessianType == HST_IDENTITY ) return SUCCESSFUL_RETURN; /* 1) If Hessian differs from identity matrix, * return without changing the internal HessianType. */ for ( i=0; i EPS ) return SUCCESSFUL_RETURN; for ( i=0; i EPS ) || ( getAbs( H[j*NVMAX + i] ) > EPS ) ) return SUCCESSFUL_RETURN; } /* 2) If this point is reached, Hessian equals the idetity matrix. */ hessianType = HST_IDENTITY; return SUCCESSFUL_RETURN; } /* * s e t u p S u b j e c t T o T y p e */ returnValue QProblemB::setupSubjectToType( ) { int i; int nV = getNV( ); /* 1) Check if lower bounds are present. */ bounds.setNoLower( BT_TRUE ); for( i=0; i -INFTY ) { bounds.setNoLower( BT_FALSE ); break; } /* 2) Check if upper bounds are present. */ bounds.setNoUpper( BT_TRUE ); for( i=0; i INFTY - BOUNDTOL ) ) { bounds.setType( i,ST_UNBOUNDED ); ++nUV; } else { if ( lb[i] > ub[i] - BOUNDTOL ) { bounds.setType( i,ST_EQUALITY ); ++nFV; } else { bounds.setType( i,ST_BOUNDED ); } } /* 4) Set dimensions of bounds structure. */ bounds.setNFV( nFV ); bounds.setNUV( nUV ); bounds.setNBV( nV - nFV - nUV ); return SUCCESSFUL_RETURN; } /* * c h o l e s k y D e c o m p o s i t i o n */ returnValue QProblemB::setupCholeskyDecomposition( ) { int i, j, k, ii, jj; int nV = getNV( ); int nFR = getNFR( ); /* If Hessian flag is false, it means that H & R already contain Cholesky * factorization -- provided from outside. */ if (hasHessian == BT_FALSE) return SUCCESSFUL_RETURN; /* 1) Initialises R with all zeros. */ for( i=0; i 0 ) { int FR_idx[NVMAX]; if ( bounds.getFree( )->getNumberArray( FR_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_INDEXLIST_CORRUPTED ); /* R'*R = H */ real_t sum; real_t inv; for( i=0; i=0; --k ) sum -= R[k*NVMAX + i] * R[k*NVMAX + i]; if ( sum > 0.0 ) { R[i*NVMAX + i] = sqrt( sum ); inv = 1.0 / R[i*NVMAX + i]; } else { hessianType = HST_SEMIDEF; return THROWERROR( RET_HESSIAN_NOT_SPD ); } /* j > i */ for( j=(i+1); j=0; --k ) sum -= R[k*NVMAX + i] * R[k*NVMAX + j]; R[i*NVMAX + j] = sum * inv; } } } } return SUCCESSFUL_RETURN; } /* * s o l v e I n i t i a l Q P */ returnValue QProblemB::solveInitialQP( const real_t* const xOpt, const real_t* const yOpt, const Bounds* const guessedBounds, int& nWSR, real_t* const cputime ) { int i, nFR; int nV = getNV( ); /* start runtime measurement */ real_t starttime = 0.0; if ( cputime != 0 ) starttime = getCPUtime( ); status = QPS_NOTINITIALISED; /* I) ANALYSE QP DATA: */ /* 1) Check if Hessian happens to be the identity matrix. */ if ( checkForIdentityHessian( ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_INIT_FAILED ); /* 2) Setup type of bounds (i.e. unbounded, implicitly fixed etc.). */ if ( setupSubjectToType( ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_INIT_FAILED ); status = QPS_PREPARINGAUXILIARYQP; /* II) SETUP AUXILIARY QP WITH GIVEN OPTIMAL SOLUTION: */ /* 1) Setup bounds data structure. */ if ( bounds.setupAllFree( ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_INIT_FAILED ); /* 2) Setup optimal primal/dual solution for auxiliary QP. */ if ( setupAuxiliaryQPsolution( xOpt,yOpt ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_INIT_FAILED ); /* 3) Obtain linear independent working set for auxiliary QP. */ static Bounds auxiliaryBounds; auxiliaryBounds.init( nV ); if ( obtainAuxiliaryWorkingSet( xOpt,yOpt,guessedBounds, &auxiliaryBounds ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_INIT_FAILED ); /* 4) Setup working set of auxiliary QP and setup cholesky decomposition. */ if ( setupAuxiliaryWorkingSet( &auxiliaryBounds,BT_TRUE ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_INIT_FAILED ); nFR = getNFR(); /* At the moment we can only provide a Cholesky of the Hessian if * the solver is cold-started. */ if (hasCholesky == BT_FALSE || nFR != nV) if (setupCholeskyDecomposition() != SUCCESSFUL_RETURN) return THROWERROR( RET_INIT_FAILED_CHOLESKY ); /* 5) Store original QP formulation... */ real_t g_original[NVMAX]; real_t lb_original[NVMAX]; real_t ub_original[NVMAX]; for( i=0; isetupBound( i,ST_LOWER ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); } else { if ( auxiliaryBounds->setupBound( i,guessedBounds->getStatus( i ) ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); } } } else /* No initial working set specified. */ { if ( ( xOpt != 0 ) && ( yOpt == 0 ) ) { /* Obtain initial working set by "clipping". */ for( i=0; isetupBound( i,ST_LOWER ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); continue; } if ( xOpt[i] >= ub[i] - BOUNDTOL ) { if ( auxiliaryBounds->setupBound( i,ST_UPPER ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); continue; } /* Moreover, add all implictly fixed variables if specified. */ if ( bounds.getType( i ) == ST_EQUALITY ) { if ( auxiliaryBounds->setupBound( i,ST_LOWER ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); } else { if ( auxiliaryBounds->setupBound( i,ST_INACTIVE ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); } } } if ( ( xOpt == 0 ) && ( yOpt != 0 ) ) { /* Obtain initial working set in accordance to sign of dual solution vector. */ for( i=0; i ZERO ) { if ( auxiliaryBounds->setupBound( i,ST_LOWER ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); continue; } if ( yOpt[i] < -ZERO ) { if ( auxiliaryBounds->setupBound( i,ST_UPPER ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); continue; } /* Moreover, add all implictly fixed variables if specified. */ if ( bounds.getType( i ) == ST_EQUALITY ) { if ( auxiliaryBounds->setupBound( i,ST_LOWER ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); } else { if ( auxiliaryBounds->setupBound( i,ST_INACTIVE ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); } } } /* If xOpt and yOpt are null pointer and no initial working is specified, * start with empty working set (or implicitly fixed bounds only) * for auxiliary QP. */ if ( ( xOpt == 0 ) && ( yOpt == 0 ) ) { for( i=0; isetupBound( i,ST_LOWER ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); } else { if ( auxiliaryBounds->setupBound( i,ST_INACTIVE ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); } } } } return SUCCESSFUL_RETURN; } /* * s e t u p A u x i l i a r y W o r k i n g S e t */ returnValue QProblemB::setupAuxiliaryWorkingSet( const Bounds* const auxiliaryBounds, BooleanType setupAfresh ) { int i; int nV = getNV( ); /* consistency checks */ if ( auxiliaryBounds != 0 ) { for( i=0; igetStatus( i ) == ST_UNDEFINED ) ) return THROWERROR( RET_UNKNOWN_BUG ); } else { return THROWERROR( RET_INVALID_ARGUMENTS ); } /* I) SETUP CHOLESKY FLAG: * Cholesky decomposition shall only be updated if working set * shall be updated (i.e. NOT setup afresh!) */ BooleanType updateCholesky; if ( setupAfresh == BT_TRUE ) updateCholesky = BT_FALSE; else updateCholesky = BT_TRUE; /* II) REMOVE FORMERLY ACTIVE BOUNDS (IF NECESSARY): */ if ( setupAfresh == BT_FALSE ) { /* Remove all active bounds that shall be inactive AND * all active bounds that are active at the wrong bound. */ for( i=0; igetStatus( i ) != ST_LOWER ) ) if ( removeBound( i,updateCholesky ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_SETUP_WORKINGSET_FAILED ); if ( ( bounds.getStatus( i ) == ST_UPPER ) && ( auxiliaryBounds->getStatus( i ) != ST_UPPER ) ) if ( removeBound( i,updateCholesky ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_SETUP_WORKINGSET_FAILED ); } } /* III) ADD NEWLY ACTIVE BOUNDS: */ /* Add all inactive bounds that shall be active AND * all formerly active bounds that have been active at the wrong bound. */ for( i=0; igetStatus( i ) != ST_INACTIVE ) ) { if ( addBound( i,auxiliaryBounds->getStatus( i ),updateCholesky ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_SETUP_WORKINGSET_FAILED ); } } return SUCCESSFUL_RETURN; } /* * s e t u p A u x i l i a r y Q P s o l u t i o n */ returnValue QProblemB::setupAuxiliaryQPsolution( const real_t* const xOpt, const real_t* const yOpt ) { int i; int nV = getNV( ); /* Setup primal/dual solution vectors for auxiliary initial QP: * if a null pointer is passed, a zero vector is assigned; * old solution vector is kept if pointer to internal solution vector is passed. */ if ( xOpt != 0 ) { if ( xOpt != x ) for( i=0; igetIndex( number ); real_t c, s; /* 2) Use row-wise Givens rotations to restore upper triangular form of R. */ for( i=number_idx+1; ith column and ... */ for( i=0; igetNumberArray( FR_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_REMOVEBOUND_FAILED ); /* 1) Calculate new column of cholesky decomposition. */ real_t rhs[NVMAX]; real_t r[NVMAX]; real_t r0 = H[number*NVMAX + number]; for( i=0; i 0.0 ) R[nFR*NVMAX + nFR] = sqrt( r0 ); else { hessianType = HST_SEMIDEF; return THROWERROR( RET_HESSIAN_NOT_SPD ); } return SUCCESSFUL_RETURN; } /* * b a c k s o l v e R (CODE DUPLICATED IN QProblem CLASS!!!) */ returnValue QProblemB::backsolveR( const real_t* const b, BooleanType transposed, real_t* const a ) { /* Call standard backsolve procedure (i.e. removingBound == BT_FALSE). */ return backsolveR( b,transposed,BT_FALSE,a ); } /* * b a c k s o l v e R (CODE DUPLICATED IN QProblem CLASS!!!) */ returnValue QProblemB::backsolveR( const real_t* const b, BooleanType transposed, BooleanType removingBound, real_t* const a ) { int i, j; int nR = getNZ( ); real_t sum; /* if backsolve is called while removing a bound, reduce nZ by one. */ if ( removingBound == BT_TRUE ) --nR; /* nothing to do */ if ( nR <= 0 ) return SUCCESSFUL_RETURN; /* Solve Ra = b, where R might be transposed. */ if ( transposed == BT_FALSE ) { /* solve Ra = b */ for( i=(nR-1); i>=0; --i ) { sum = b[i]; for( j=(i+1); j ZERO ) a[i] = sum / R[i*NVMAX + i]; else return THROWERROR( RET_DIV_BY_ZERO ); } } else { /* solve R^T*a = b */ for( i=0; i ZERO ) a[i] = sum / R[i*NVMAX + i]; else return THROWERROR( RET_DIV_BY_ZERO ); } } return SUCCESSFUL_RETURN; } /* * h o t s t a r t _ d e t e r m i n e D a t a S h i f t */ returnValue QProblemB::hotstart_determineDataShift( const int* const FX_idx, const real_t* const g_new, const real_t* const lb_new, const real_t* const ub_new, real_t* const delta_g, real_t* const delta_lb, real_t* const delta_ub, BooleanType& Delta_bB_isZero ) { int i, ii; int nV = getNV( ); int nFX = getNFX( ); /* 1) Calculate shift directions. */ for( i=0; i EPS ) || ( getAbs( delta_ub[ii] ) > EPS ) ) { Delta_bB_isZero = BT_FALSE; break; } } return SUCCESSFUL_RETURN; } /* * a r e B o u n d s C o n s i s t e n t */ BooleanType QProblemB::areBoundsConsistent( const real_t* const delta_lb, const real_t* const delta_ub ) const { int i; /* Check if delta_lb[i] is greater than delta_ub[i] * for a component i whose bounds are already (numerically) equal. */ for( i=0; i ub[i] - BOUNDTOL ) && ( delta_lb[i] > delta_ub[i] + EPS ) ) return BT_FALSE; return BT_TRUE; } /* * s e t u p Q P d a t a */ returnValue QProblemB::setupQPdata( const real_t* const _H, const real_t* const _R, const real_t* const _g, const real_t* const _lb, const real_t* const _ub ) { int i, j; int nV = getNV( ); /* 1) Setup Hessian matrix and it's Cholesky factorization. */ if (_H != 0) { for( i=0; i 0 ) { for( i=0; i 0 ) { /* auxiliary variables */ real_t delta_xFRz_TMP[NVMAX]; real_t delta_xFRz_RHS[NVMAX]; /* Determine delta_xFRz. */ if ( Delta_bB_isZero == BT_FALSE ) { for( i=0; i 0 ) { for( i=0; i= 0.0 ) ) { tau_tmp = y[ii] / ( -delta_yFX[i] ); if ( tau_tmp < tau_new ) { if ( tau_tmp >= 0.0 ) { tau_new = tau_tmp; BC_idx = ii; BC_status = ST_INACTIVE; } } } } else { /* 2) Active upper bounds. */ if ( ( delta_yFX[i] > ZERO ) && ( y[ii] <= 0.0 ) ) { tau_tmp = y[ii] / ( -delta_yFX[i] ); if ( tau_tmp < tau_new ) { if ( tau_tmp >= 0.0 ) { tau_new = tau_tmp; BC_idx = ii; BC_status = ST_INACTIVE; } } } } } } /* II) DETERMINE MAXIMUM PRIMAL STEPLENGTH, i.e. ensure that * inactive bounds remain valid (ignoring unbounded variables). */ /* 1) Inactive lower bounds. */ if ( bounds.isNoLower( ) == BT_FALSE ) { for( i=0; i delta_xFR[i] ) { if ( x[ii] > lb[ii] ) tau_tmp = ( x[ii] - lb[ii] ) / ( delta_lb[ii] - delta_xFR[i] ); else tau_tmp = 0.0; if ( tau_tmp < tau_new ) { if ( tau_tmp >= 0.0 ) { tau_new = tau_tmp; BC_idx = ii; BC_status = ST_LOWER; } } } } } } /* 2) Inactive upper bounds. */ if ( bounds.isNoUpper( ) == BT_FALSE ) { for( i=0; i= 0.0 ) { tau_new = tau_tmp; BC_idx = ii; BC_status = ST_UPPER; } } } } } } /* III) SET MAXIMUM HOMOTOPY STEPLENGTH */ tau = tau_new; if ( printlevel == PL_HIGH ) { #ifdef PC_DEBUG char messageString[80]; if ( BC_status == ST_UNDEFINED ) sprintf( messageString,"Stepsize is %.6e!",tau ); else sprintf( messageString,"Stepsize is %.6e! (BC_idx = %d, BC_status = %d)",tau,BC_idx,BC_status ); getGlobalMessageHandler( )->throwInfo( RET_STEPSIZE_NONPOSITIVE,messageString,__FUNCTION__,__FILE__,__LINE__,VS_VISIBLE ); #endif } return SUCCESSFUL_RETURN; } /* * h o t s t a r t _ p e r f o r m S t e p */ returnValue QProblemB::hotstart_performStep( const int* const FR_idx, const int* const FX_idx, const real_t* const delta_g, const real_t* const delta_lb, const real_t* const delta_ub, const real_t* const delta_xFX, const real_t* const delta_xFR, const real_t* const delta_yFX, int BC_idx, SubjectToStatus BC_status ) { int i, ii; int nV = getNV( ); int nFR = getNFR( ); int nFX = getNFX( ); /* I) CHECK BOUNDS' CONSISTENCY */ if ( areBoundsConsistent( delta_lb,delta_ub ) == BT_FALSE ) { infeasible = BT_TRUE; tau = 0.0; return THROWERROR( RET_QP_INFEASIBLE ); } /* II) GO TO ACTIVE SET CHANGE */ if ( tau > ZERO ) { /* 1) Perform step in primal und dual space. */ for( i=0; ithrowWarning( RET_STEPSIZE,messageString,__FUNCTION__,__FILE__,__LINE__,VS_VISIBLE ); #endif } /* setup output preferences */ #ifdef PC_DEBUG char messageString[80]; VisibilityStatus visibilityStatus; if ( printlevel == PL_HIGH ) visibilityStatus = VS_VISIBLE; else visibilityStatus = VS_HIDDEN; #endif /* III) UPDATE ACTIVE SET */ switch ( BC_status ) { /* Optimal solution found as no working set change detected. */ case ST_UNDEFINED: return RET_OPTIMAL_SOLUTION_FOUND; /* Remove one variable from active set. */ case ST_INACTIVE: #ifdef PC_DEBUG sprintf( messageString,"bound no. %d.", BC_idx ); getGlobalMessageHandler( )->throwInfo( RET_REMOVE_FROM_ACTIVESET,messageString,__FUNCTION__,__FILE__,__LINE__,visibilityStatus ); #endif if ( removeBound( BC_idx,BT_TRUE ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_REMOVE_FROM_ACTIVESET_FAILED ); y[BC_idx] = 0.0; break; /* Add one variable to active set. */ default: #ifdef PC_DEBUG if ( BC_status == ST_LOWER ) sprintf( messageString,"lower bound no. %d.", BC_idx ); else sprintf( messageString,"upper bound no. %d.", BC_idx ); getGlobalMessageHandler( )->throwInfo( RET_ADD_TO_ACTIVESET,messageString,__FUNCTION__,__FILE__,__LINE__,visibilityStatus ); #endif if ( addBound( BC_idx,BC_status,BT_TRUE ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_ADD_TO_ACTIVESET_FAILED ); break; } return SUCCESSFUL_RETURN; } #ifdef PC_DEBUG /* Define print functions only for debugging! */ /* * p r i n t I t e r a t i o n */ returnValue QProblemB::printIteration( int iteration, int BC_idx, SubjectToStatus BC_status ) { char myPrintfString[160]; /* consistency check */ if ( iteration < 0 ) return THROWERROR( RET_INVALID_ARGUMENTS ); /* nothing to do */ if ( printlevel != PL_MEDIUM ) return SUCCESSFUL_RETURN; /* 1) Print header at first iteration. */ if ( iteration == 0 ) { sprintf( myPrintfString,"\n############## qpOASES -- QP NO.%4.1d ###############\n", count ); myPrintf( myPrintfString ); sprintf( myPrintfString," Iter | StepLength | Info | nFX \n" ); myPrintf( myPrintfString ); } /* 2) Print iteration line. */ if ( BC_status == ST_UNDEFINED ) { sprintf( myPrintfString," %4.1d | %1.5e | QP SOLVED | %4.1d \n", iteration,tau,getNFX( ) ); myPrintf( myPrintfString ); } else { char info[8]; if ( BC_status == ST_INACTIVE ) sprintf( info,"REM BND" ); else sprintf( info,"ADD BND" ); sprintf( myPrintfString," %4.1d | %1.5e | %s%4.1d | %4.1d \n", iteration,tau,info,BC_idx,getNFX( ) ); myPrintf( myPrintfString ); } return SUCCESSFUL_RETURN; } #endif /* PC_DEBUG */ /* * c h e c k K K T c o n d i t i o n s */ returnValue QProblemB::checkKKTconditions( ) { #ifdef __PERFORM_KKT_TEST__ int i, j; int nV = getNV( ); real_t tmp; real_t maxKKTviolation = 0.0; /* 1) Check for Hx + g - y*A' = 0 (here: A = Id). */ for( i=0; i maxKKTviolation ) maxKKTviolation = getAbs( tmp ); } /* 2) Check for lb <= x <= ub. */ for( i=0; i maxKKTviolation ) maxKKTviolation = lb[i] - x[i]; if ( x[i] - ub[i] > maxKKTviolation ) maxKKTviolation = x[i] - ub[i]; } /* 3) Check for correct sign of y and for complementary slackness. */ for( i=0; i maxKKTviolation ) maxKKTviolation = -y[i]; if ( getAbs( ( x[i] - lb[i] ) * y[i] ) > maxKKTviolation ) maxKKTviolation = getAbs( ( x[i] - lb[i] ) * y[i] ); break; case ST_UPPER: if ( y[i] > maxKKTviolation ) maxKKTviolation = y[i]; if ( getAbs( ( ub[i] - x[i] ) * y[i] ) > maxKKTviolation ) maxKKTviolation = getAbs( ( ub[i] - x[i] ) * y[i] ); break; default: /* inactive */ if ( getAbs( y[i] ) > maxKKTviolation ) maxKKTviolation = getAbs( y[i] ); break; } } if ( maxKKTviolation > CRITICALACCURACY ) return RET_NO_SOLUTION; if ( maxKKTviolation > DESIREDACCURACY ) return RET_INACCURATE_SOLUTION; #endif /* __PERFORM_KKT_TEST__ */ return SUCCESSFUL_RETURN; } /* * end of file */