/* * 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/QProblem.cpp * \author Hans Joachim Ferreau * \version 1.3embedded * \date 2007-2008 * * Implementation of the QProblem class which is able to use the newly * developed online active set strategy for parametric quadratic programming. */ #include #include void printmatrix2(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"); } //#define __PERFORM_KKT_TEST__ /***************************************************************************** * P U B L I C * *****************************************************************************/ /* * Q P r o b l e m */ QProblem::QProblem( ) : QProblemB( ) { constraints.init( 0 ); sizeT = 0; cyclingManager.init( 0,0 ); } /* * Q P r o b l e m */ QProblem::QProblem( int _nV, int _nC ) : QProblemB( _nV ) { /* consistency checks */ if ( _nV <= 0 ) _nV = 1; if ( _nC < 0 ) { _nC = 0; THROWERROR( RET_INVALID_ARGUMENTS ); } constraints.init( _nC ); sizeT = _nC; if ( _nC > _nV ) sizeT = _nV; cyclingManager.init( _nV,_nC ); } /* * Q P r o b l e m */ QProblem::QProblem( const QProblem& rhs ) : QProblemB( rhs ) { int i, j; int _nV = rhs.bounds.getNV( ); int _nC = rhs.constraints.getNC( ); for( i=0; i<_nC; ++i ) for( j=0; j<_nV; ++j ) A[i*NVMAX + j] = rhs.A[i*NVMAX + j]; for( i=0; i<_nC; ++i ) lbA[i] = rhs.lbA[i]; for( i=0; i<_nC; ++i ) ubA[i] = rhs.ubA[i]; constraints = rhs.constraints; for( i=0; i<(_nV+_nC); ++i ) y[i] = rhs.y[i]; sizeT = rhs.sizeT; 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 ); if ( constraints.getActive( )->getNumberArray( AC_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_HOTSTART_FAILED ); if ( constraints.getInactive( )->getNumberArray( IAC_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_HOTSTART_FAILED ); /* 2) Detemination of shift direction of the gradient and the (constraints') bounds. */ returnvalue = hotstart_determineDataShift( FX_idx, AC_idx, g_new,lbA_new,ubA_new,lb_new,ub_new, delta_g,delta_lbA,delta_ubA,delta_lb,delta_ub, Delta_bC_isZero, 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,AC_idx, delta_g,delta_lbA,delta_ubA,delta_lb,delta_ub, Delta_bC_isZero, Delta_bB_isZero, delta_xFX,delta_xFR,delta_yAC,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,AC_idx,IAC_idx, delta_lbA,delta_ubA,delta_lb,delta_ub, delta_xFX,delta_xFR,delta_yAC,delta_yFX,delta_Ax, BC_idx,BC_status,BC_isBound ); if ( returnvalue != SUCCESSFUL_RETURN ) { nWSR = l; THROWERROR( RET_STEPLENGTH_DETERMINATION_FAILED ); return returnvalue; } /* 5) Realisation of the homotopy step. */ returnvalue = hotstart_performStep( FR_idx,FX_idx,AC_idx,IAC_idx, delta_g,delta_lbA,delta_ubA,delta_lb,delta_ub, delta_xFX,delta_xFR,delta_yAC,delta_yFX,delta_Ax, BC_idx,BC_status,BC_isBound ); 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,BC_isBound ) != 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 ( isInfeasible( ) == 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,BC_isBound ) != 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 QProblem::getNZ( ) { /* nZ = nFR - nAC */ return bounds.getFree( )->getLength( ) - constraints.getActive( )->getLength( ); } /* * g e t D u a l S o l u t i o n */ returnValue QProblem::getDualSolution( real_t* const yOpt ) const { int i; /* return optimal dual solution vector * only if current QP has been solved */ if ( ( getStatus( ) == QPS_AUXILIARYQPSOLVED ) || ( getStatus( ) == QPS_HOMOTOPYQPSOLVED ) || ( getStatus( ) == QPS_SOLVED ) ) { for( i=0; i -INFTY ) { constraints.setNoLower( BT_FALSE ); break; } } /* 2) Check if upper constraints' bounds are present. */ constraints.setNoUpper( BT_TRUE ); for( i=0; i INFTY - BOUNDTOL ) ) { constraints.setType( i,ST_UNBOUNDED ); ++nUC; } else { if ( lbA[i] > ubA[i] - BOUNDTOL ) { constraints.setType( i,ST_EQUALITY ); ++nEC; } else { constraints.setType( i,ST_BOUNDED ); } } } /* 4) Set dimensions of constraints structure. */ constraints.setNEC( nEC ); constraints.setNUC( nUC ); constraints.setNIC( nC - nEC - nUC ); return SUCCESSFUL_RETURN; } /* * c h o l e s k y D e c o m p o s i t i o n P r o j e c t e d */ returnValue QProblem::setupCholeskyDecompositionProjected( ) { int i, j, k, ii, kk; int nV = getNV( ); int nFR = getNFR( ); int nZ = getNZ( ); /* 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 ); #if 0 real_t HZ[NVMAX*NVMAX]; real_t ZHZ[NVMAX*NVMAX]; /* calculate H*Z */ 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 ); } for( j=(i+1); j=0; --k ) sum -= R[k*NVMAX + i] * R[k*NVMAX + j]; R[i*NVMAX + j] = sum * inv; } } #else real_t HZ[NVMAX]; real_t ZHZ[NVMAX]; real_t sum, inv; for (j = 0; j < nZ; ++j) { /* Cache one column of Z. */ for (i = 0; i < NVMAX; ++i) ZHZ[i] = Q[i * NVMAX + j]; /* Create one column of the product H * Z. */ for (i = 0; i < nFR; ++i) { ii = FR_idx[i]; sum = 0.0; for (k = 0; k < nFR; ++k) { kk = FR_idx[k]; sum += H[ii * NVMAX + kk] * ZHZ[kk]; } HZ[ii] = sum; } /* Create one column of the product Z^T * H * Z. */ for (i = j; i < nZ; ++i) ZHZ[ i ] = 0.0; for (k = 0; k < nFR; ++k) { kk = FR_idx[k]; real_t q = HZ[kk]; for (i = j; i < nZ; ++i) { ZHZ[i] += Q[kk * NVMAX + i] * q; } } /* Use the computed column to update the factorization. */ /* j == i */ sum = ZHZ[j]; for (k = (j - 1); k >= 0; --k) sum -= R[k * NVMAX + j] * R[k * NVMAX + j]; if (sum > 0.0) { R[j * NVMAX + j] = sqrt(sum); inv = 1.0 / R[j * NVMAX + j]; } else { hessianType = HST_SEMIDEF; return THROWERROR( RET_HESSIAN_NOT_SPD ); } for (i = (j + 1); i < nZ; ++i) { sum = ZHZ[i]; for (k = (j - 1); k >= 0; --k) sum -= R[k * NVMAX + j] * R[k * NVMAX + i]; R[j * NVMAX + i] = sum * inv; } } #endif } } return SUCCESSFUL_RETURN; } /* * s e t u p T Q f a c t o r i s a t i o n */ returnValue QProblem::setupTQfactorisation( ) { int i, j, ii; int nV = getNV( ); int nFR = getNFR( ); int FR_idx[NVMAX]; if ( bounds.getFree( )->getNumberArray( FR_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_INDEXLIST_CORRUPTED ); /* 1) Set Q to unity matrix. */ for( i=0; igetStatus( i ); if ( constraints.getType( i ) == ST_EQUALITY ) { if ( auxiliaryConstraints->setupConstraint( i,ST_LOWER ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); } else { if ( auxiliaryConstraints->setupConstraint( i,guessedStatus ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); } } } else /* No initial working set specified. */ { /* Obtain initial working set by "clipping". */ if ( ( xOpt != 0 ) && ( yOpt == 0 ) ) { for( i=0; isetupConstraint( i,ST_LOWER ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); continue; } if ( Ax[i] >= ubA[i] - BOUNDTOL ) { if ( auxiliaryConstraints->setupConstraint( i,ST_UPPER ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); continue; } /* Moreover, add all equality constraints if specified. */ if ( constraints.getType( i ) == ST_EQUALITY ) { if ( auxiliaryConstraints->setupConstraint( i,ST_LOWER ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); } else { if ( auxiliaryConstraints->setupConstraint( i,ST_INACTIVE ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); } } } /* Obtain initial working set in accordance to sign of dual solution vector. */ if ( ( xOpt == 0 ) && ( yOpt != 0 ) ) { for( i=0; i ZERO ) { if ( auxiliaryConstraints->setupConstraint( i,ST_LOWER ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); continue; } if ( yOpt[nV+i] < -ZERO ) { if ( auxiliaryConstraints->setupConstraint( i,ST_UPPER ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); continue; } /* Moreover, add all equality constraints if specified. */ if ( constraints.getType( i ) == ST_EQUALITY ) { if ( auxiliaryConstraints->setupConstraint( i,ST_LOWER ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); } else { if ( auxiliaryConstraints->setupConstraint( 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 and equality constraints only) * for auxiliary QP. */ if ( ( xOpt == 0 ) && ( yOpt == 0 ) ) { for( i=0; isetupConstraint( i,ST_LOWER ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED ); } else { if ( auxiliaryConstraints->setupConstraint( 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 QProblem::setupAuxiliaryWorkingSet( const Bounds* const auxiliaryBounds, const Constraints* const auxiliaryConstraints, BooleanType setupAfresh ) { int i; int nV = getNV( ); int nC = getNC( ); /* consistency checks */ if ( auxiliaryBounds != 0 ) { for( i=0; igetStatus( i ) == ST_UNDEFINED ) ) return THROWERROR( RET_UNKNOWN_BUG ); } else { return THROWERROR( RET_INVALID_ARGUMENTS ); } if ( auxiliaryConstraints != 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 (CONSTRAINTS') BOUNDS (IF NECESSARY): */ if ( setupAfresh == BT_FALSE ) { /* 1) Remove all active constraints that shall be inactive AND * all active constraints that are active at the wrong bound. */ for( i=0; igetStatus( i ) != ST_LOWER ) ) if ( removeConstraint( i,updateCholesky ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_SETUP_WORKINGSET_FAILED ); if ( ( constraints.getStatus( i ) == ST_UPPER ) && ( auxiliaryConstraints->getStatus( i ) != ST_UPPER ) ) if ( removeConstraint( i,updateCholesky ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_SETUP_WORKINGSET_FAILED ); } /* 2) 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 (CONSTRAINTS') BOUNDS: */ /* 1) 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 ) ) { /* Add bound only if it is linearly independent from the current working set. */ if ( addBound_checkLI( i ) == RET_LINEARLY_INDEPENDENT ) { if ( addBound( i,auxiliaryBounds->getStatus( i ),updateCholesky ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_SETUP_WORKINGSET_FAILED ); } } } /* 2) Add all inactive constraints that shall be active AND * all formerly active constraints that have been active at the wrong bound. */ for( i=0; igetStatus( i ) == ST_LOWER ) || ( auxiliaryConstraints->getStatus( i ) == ST_UPPER ) ) { /* formerly inactive */ if ( constraints.getStatus( i ) == ST_INACTIVE ) { /* Add constraint only if it is linearly independent from the current working set. */ if ( addConstraint_checkLI( i ) == RET_LINEARLY_INDEPENDENT ) { if ( addConstraint( i,auxiliaryConstraints->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 QProblem::setupAuxiliaryQPsolution( const real_t* const xOpt, const real_t* const yOpt ) { int i, j; int nV = getNV( ); int nC = getNC( ); /* Setup primal/dual solution vector 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 vevtor is passed. */ if ( xOpt != 0 ) { if ( xOpt != x ) for( i=0; igetStatus( i ) == ST_LOWER ) lb[i] = x[i]; else lb[i] = x[i] - BOUNDRELAXATION; if ( auxiliaryBounds->getStatus( i ) == ST_UPPER ) ub[i] = x[i]; else ub[i] = x[i] + BOUNDRELAXATION; } } break; case ST_LOWER: lb[i] = x[i]; if ( bounds.getType( i ) == ST_EQUALITY ) { ub[i] = x[i]; } else { if ( useRelaxation == BT_TRUE ) ub[i] = x[i] + BOUNDRELAXATION; } break; case ST_UPPER: ub[i] = x[i]; if ( bounds.getType( i ) == ST_EQUALITY ) { lb[i] = x[i]; } else { if ( useRelaxation == BT_TRUE ) lb[i] = x[i] - BOUNDRELAXATION; } break; default: return THROWERROR( RET_UNKNOWN_BUG ); } } /* 2) Setup constraints vectors. */ for ( i=0; igetStatus( i ) == ST_LOWER ) lbA[i] = Ax[i]; else lbA[i] = Ax[i] - BOUNDRELAXATION; if ( auxiliaryConstraints->getStatus( i ) == ST_UPPER ) ubA[i] = Ax[i]; else ubA[i] = Ax[i] + BOUNDRELAXATION; } } break; case ST_LOWER: lbA[i] = Ax[i]; if ( constraints.getType( i ) == ST_EQUALITY ) { ubA[i] = Ax[i]; } else { if ( useRelaxation == BT_TRUE ) ubA[i] = Ax[i] + BOUNDRELAXATION; } break; case ST_UPPER: ubA[i] = Ax[i]; if ( constraints.getType( i ) == ST_EQUALITY ) { lbA[i] = Ax[i]; } else { if ( useRelaxation == BT_TRUE ) lbA[i] = Ax[i] - BOUNDRELAXATION; } break; default: return THROWERROR( RET_UNKNOWN_BUG ); } } return SUCCESSFUL_RETURN; } /* * a d d C o n s t r a i n t */ returnValue QProblem::addConstraint( int number, SubjectToStatus C_status, BooleanType updateCholesky ) { int i, j, ii; /* consistency checks */ if ( constraints.getStatus( number ) != ST_INACTIVE ) return THROWERROR( RET_CONSTRAINT_ALREADY_ACTIVE ); if ( ( constraints.getNC( ) - getNAC( ) ) == constraints.getNUC( ) ) return THROWERROR( RET_ALL_CONSTRAINTS_ACTIVE ); if ( ( getStatus( ) == QPS_NOTINITIALISED ) || ( getStatus( ) == QPS_AUXILIARYQPSOLVED ) || ( getStatus( ) == QPS_HOMOTOPYQPSOLVED ) || ( getStatus( ) == QPS_SOLVED ) ) { return THROWERROR( RET_UNKNOWN_BUG ); } /* I) ENSURE LINEAR INDEPENDENCE OF THE WORKING SET, * i.e. remove a constraint or bound if linear dependence occurs. */ /* check for LI only if Cholesky decomposition shall be updated! */ if ( updateCholesky == BT_TRUE ) { returnValue ensureLIreturnvalue = addConstraint_ensureLI( number,C_status ); switch ( ensureLIreturnvalue ) { case SUCCESSFUL_RETURN: break; case RET_LI_RESOLVED: break; case RET_ENSURELI_FAILED_NOINDEX: return THROWERROR( RET_ADDCONSTRAINT_FAILED_INFEASIBILITY ); case RET_ENSURELI_FAILED_CYCLING: return THROWERROR( RET_ADDCONSTRAINT_FAILED_INFEASIBILITY ); default: return THROWERROR( RET_ENSURELI_FAILED ); } } /* some definitions */ int nFR = getNFR( ); int nAC = getNAC( ); int nZ = getNZ( ); int tcol = sizeT - nAC; int FR_idx[NVMAX]; if ( bounds.getFree( )->getNumberArray( FR_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_ADDCONSTRAINT_FAILED ); real_t aFR[NVMAX]; real_t wZ[NVMAX]; for( i=0; i 0 ) { for( j=0; j 0 ) { /* II) RESTORE TRIANGULAR FORM OF T: */ /* Use column-wise Givens rotations to restore reverse triangular form * of T, simultanenous change of Q (i.e. Z) and R. */ for( j=0; jgetNumberArray( FR_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_INDEXLIST_CORRUPTED ); /* Check if constraint is linearly independent from the the active ones (<=> is element of null space of Afr). */ real_t sum; for( i=0; i 10.0*EPS ) return RET_LINEARLY_INDEPENDENT; } return RET_LINEARLY_DEPENDENT; } /* * a d d C o n s t r a i n t _ e n s u r e L I */ returnValue QProblem::addConstraint_ensureLI( int number, SubjectToStatus C_status ) { int i, j, ii, jj; int nV = getNV( ); int nFR = getNFR( ); int nFX = getNFX( ); int nAC = getNAC( ); int nZ = getNZ( ); /* I) Check if new constraint is linearly independent from the active ones. */ returnValue returnvalueCheckLI = addConstraint_checkLI( number ); if ( returnvalueCheckLI == RET_INDEXLIST_CORRUPTED ) return THROWERROR( RET_ENSURELI_FAILED ); if ( returnvalueCheckLI == RET_LINEARLY_INDEPENDENT ) return SUCCESSFUL_RETURN; /* II) NEW CONSTRAINT IS LINEARLY DEPENDENT: */ /* 1) Determine coefficients of linear combination, * cf. M.J. Best. Applied Mathematics and Parallel Computing, chapter: * An Algorithm for the Solution of the Parametric Quadratic Programming * Problem, pages 57-76. Physica-Verlag, Heidelberg, 1996. */ int FR_idx[NVMAX]; if ( bounds.getFree( )->getNumberArray( FR_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_ENSURELI_FAILED ); int FX_idx[NVMAX]; if ( bounds.getFixed( )->getNumberArray( FX_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_ENSURELI_FAILED ); real_t xiC[NCMAX_ALLOC]; real_t xiC_TMP[NCMAX_ALLOC]; real_t xiB[NVMAX]; /* 2) Calculate xiC */ if ( nAC > 0 ) { if ( C_status == ST_LOWER ) { for( i=0; igetNumberArray( AC_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_ENSURELI_FAILED ); if ( C_status == ST_LOWER ) { for( i=0; i ZERO ) && ( y[nV+ii] >= 0.0 ) ) { if ( y[nV+ii]/xiC[i] < y_min ) { y_min = y[nV+ii]/xiC[i]; y_min_number = ii; } } } else { if ( ( xiC[i] < -ZERO ) && ( y[nV+ii] <= 0.0 ) ) { if ( y[nV+ii]/xiC[i] < y_min ) { y_min = y[nV+ii]/xiC[i]; y_min_number = ii; } } } } /* 2) Bounds. */ for( i=0; i ZERO ) && ( y[ii] >= 0.0 ) ) { if ( y[ii]/xiB[i] < y_min ) { y_min = y[ii]/xiB[i]; y_min_number = ii; y_min_isBound = BT_TRUE; } } } else { if ( ( xiB[i] < -ZERO ) && ( y[ii] <= 0.0 ) ) { if ( y[ii]/xiB[i] < y_min ) { y_min = y[ii]/xiB[i]; y_min_number = ii; y_min_isBound = BT_TRUE; } } } } /* setup output preferences */ #ifdef PC_DEBUG char messageString[80]; VisibilityStatus visibilityStatus; if ( printlevel == PL_HIGH ) visibilityStatus = VS_VISIBLE; else visibilityStatus = VS_HIDDEN; #endif /* IV) REMOVE CONSTRAINT/BOUND FOR RESOLVING LINEAR DEPENDENCE: */ if ( y_min_number >= 0 ) { /* 1) Check for cycling due to infeasibility. */ if ( ( cyclingManager.getCyclingStatus( number,BT_FALSE ) == CYC_PREV_REMOVED ) && ( cyclingManager.getCyclingStatus( y_min_number,y_min_isBound ) == CYC_PREV_ADDED ) ) { infeasible = BT_TRUE; return THROWERROR( RET_ENSURELI_FAILED_CYCLING ); } else { /* set cycling data */ cyclingManager.clearCyclingData( ); cyclingManager.setCyclingStatus( number,BT_FALSE, CYC_PREV_ADDED ); cyclingManager.setCyclingStatus( y_min_number,y_min_isBound, CYC_PREV_REMOVED ); } /* 2) Update Lagrange multiplier... */ for( i=0; ithrowInfo( RET_REMOVE_FROM_ACTIVESET,messageString,__FUNCTION__,__FILE__,__LINE__,visibilityStatus ); #endif if ( removeBound( y_min_number,BT_TRUE ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_REMOVE_FROM_ACTIVESET_FAILED ); y[y_min_number] = 0.0; } else { #ifdef PC_DEBUG sprintf( messageString,"constraint no. %d.",y_min_number ); getGlobalMessageHandler( )->throwInfo( RET_REMOVE_FROM_ACTIVESET,messageString,__FUNCTION__,__FILE__,__LINE__,visibilityStatus ); #endif if ( removeConstraint( y_min_number,BT_TRUE ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_REMOVE_FROM_ACTIVESET_FAILED ); y[nV+y_min_number] = 0.0; } } else { /* no constraint/bound can be removed => QP is infeasible! */ infeasible = BT_TRUE; return THROWERROR( RET_ENSURELI_FAILED_NOINDEX ); } return getGlobalMessageHandler( )->throwInfo( RET_LI_RESOLVED,0,__FUNCTION__,__FILE__,__LINE__,VS_HIDDEN ); } /* * a d d B o u n d */ returnValue QProblem::addBound( int number, SubjectToStatus B_status, BooleanType updateCholesky ) { int i, j, ii; /* consistency checks */ if ( bounds.getStatus( number ) != ST_INACTIVE ) return THROWERROR( RET_BOUND_ALREADY_ACTIVE ); if ( getNFR( ) == bounds.getNUV( ) ) return THROWERROR( RET_ALL_BOUNDS_ACTIVE ); if ( ( getStatus( ) == QPS_NOTINITIALISED ) || ( getStatus( ) == QPS_AUXILIARYQPSOLVED ) || ( getStatus( ) == QPS_HOMOTOPYQPSOLVED ) || ( getStatus( ) == QPS_SOLVED ) ) { return THROWERROR( RET_UNKNOWN_BUG ); } /* I) ENSURE LINEAR INDEPENDENCE OF THE WORKING SET, * i.e. remove a constraint or bound if linear dependence occurs. */ /* check for LI only if Cholesky decomposition shall be updated! */ if ( updateCholesky == BT_TRUE ) { returnValue ensureLIreturnvalue = addBound_ensureLI( number,B_status ); switch ( ensureLIreturnvalue ) { case SUCCESSFUL_RETURN: break; case RET_LI_RESOLVED: break; case RET_ENSURELI_FAILED_NOINDEX: return THROWERROR( RET_ADDBOUND_FAILED_INFEASIBILITY ); case RET_ENSURELI_FAILED_CYCLING: return THROWERROR( RET_ADDBOUND_FAILED_INFEASIBILITY ); default: return THROWERROR( RET_ENSURELI_FAILED ); } } /* some definitions */ int nFR = getNFR( ); int nAC = getNAC( ); int nZ = getNZ( ); int tcol = sizeT - nAC; /* I) SWAP INDEXLIST OF FREE VARIABLES: * move the variable to be fixed to the end of the list of free variables. */ int lastfreenumber = bounds.getFree( )->getLastNumber( ); if ( lastfreenumber != number ) if ( bounds.swapFree( number,lastfreenumber ) != SUCCESSFUL_RETURN ) THROWERROR( RET_ADDBOUND_FAILED ); int FR_idx[NVMAX]; if ( bounds.getFree( )->getNumberArray( FR_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_ADDBOUND_FAILED ); real_t w[NVMAX]; /* II) ADD NEW ACTIVE BOUND TO TOP OF MATRIX T: */ /* 1) add row [wZ wY] = [Z Y](number) at the top of T: assign w */ for( i=0; i 0 ) /* ( nAC == 0 ) <=> ( nZ == nFR ) <=> Y and T are empty => nothing to do */ { /* store new column a in a temporary vector instead of shifting T one column to the left */ real_t tmp[NCMAX_ALLOC]; for( i=0; i is linearly independent from the the active ones (<=> is element of null space of Afr). */ for( i=0; i EPS ) return RET_LINEARLY_INDEPENDENT; } return RET_LINEARLY_DEPENDENT; } /* * a d d B o u n d _ e n s u r e L I */ returnValue QProblem::addBound_ensureLI( int number, SubjectToStatus B_status ) { int i, j, ii, jj; int nV = getNV( ); int nFX = getNFX( ); int nAC = getNAC( ); int nZ = getNZ( ); /* I) Check if new constraint is linearly independent from the active ones. */ returnValue returnvalueCheckLI = addBound_checkLI( number ); if ( returnvalueCheckLI == RET_LINEARLY_INDEPENDENT ) return SUCCESSFUL_RETURN; /* II) NEW BOUND IS LINEARLY DEPENDENT: */ /* 1) Determine coefficients of linear combination, * cf. M.J. Best. Applied Mathematics and Parallel Computing, chapter: * An Algorithm for the Solution of the Parametric Quadratic Programming * Problem, pages 57-76. Physica-Verlag, Heidelberg, 1996. */ int FR_idx[NVMAX]; if ( bounds.getFree( )->getNumberArray( FR_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_ENSURELI_FAILED ); int FX_idx[NVMAX]; if ( bounds.getFixed( )->getNumberArray( FX_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_ENSURELI_FAILED ); int AC_idx[NCMAX_ALLOC]; if ( constraints.getActive( )->getNumberArray( AC_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_ENSURELI_FAILED ); real_t xiC[NCMAX_ALLOC]; real_t xiC_TMP[NCMAX_ALLOC]; real_t xiB[NVMAX]; /* 2) Calculate xiC. */ if ( nAC > 0 ) { if ( B_status == ST_LOWER ) { for( i=0; i ZERO ) && ( y[nV+ii] >= 0.0 ) ) { if ( y[nV+ii]/xiC[i] < y_min ) { y_min = y[nV+ii]/xiC[i]; y_min_number = ii; } } } else { if ( ( xiC[i] < -ZERO ) && ( y[nV+ii] <= 0.0 ) ) { if ( y[nV+ii]/xiC[i] < y_min ) { y_min = y[nV+ii]/xiC[i]; y_min_number = ii; } } } } /* 2) Bounds. */ for( i=0; i ZERO ) && ( y[ii] >= 0.0 ) ) { if ( y[ii]/xiB[i] < y_min ) { y_min = y[ii]/xiB[i]; y_min_number = ii; y_min_isBound = BT_TRUE; } } } else { if ( ( xiB[i] < -ZERO ) && ( y[ii] <= 0.0 ) ) { if ( y[ii]/xiB[i] < y_min ) { y_min = y[ii]/xiB[i]; y_min_number = ii; y_min_isBound = BT_TRUE; } } } } /* setup output preferences */ #ifdef PC_DEBUG char messageString[80]; VisibilityStatus visibilityStatus; if ( printlevel == PL_HIGH ) visibilityStatus = VS_VISIBLE; else visibilityStatus = VS_HIDDEN; #endif /* IV) REMOVE CONSTRAINT/BOUND FOR RESOLVING LINEAR DEPENDENCE: */ if ( y_min_number >= 0 ) { /* 1) Check for cycling due to infeasibility. */ if ( ( cyclingManager.getCyclingStatus( number,BT_TRUE ) == CYC_PREV_REMOVED ) && ( cyclingManager.getCyclingStatus( y_min_number,y_min_isBound ) == CYC_PREV_ADDED ) ) { infeasible = BT_TRUE; return THROWERROR( RET_ENSURELI_FAILED_CYCLING ); } else { /* set cycling data */ cyclingManager.clearCyclingData( ); cyclingManager.setCyclingStatus( number,BT_TRUE, CYC_PREV_ADDED ); cyclingManager.setCyclingStatus( y_min_number,y_min_isBound, CYC_PREV_REMOVED ); } /* 2) Update Lagrange multiplier... */ for( i=0; ithrowInfo( RET_REMOVE_FROM_ACTIVESET,messageString,__FUNCTION__,__FILE__,__LINE__,visibilityStatus ); #endif if ( removeBound( y_min_number,BT_TRUE ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_REMOVE_FROM_ACTIVESET_FAILED ); y[y_min_number] = 0.0; } else { #ifdef PC_DEBUG sprintf( messageString,"constraint no. %d.",y_min_number ); getGlobalMessageHandler( )->throwInfo( RET_REMOVE_FROM_ACTIVESET,messageString,__FUNCTION__,__FILE__,__LINE__,visibilityStatus ); #endif if ( removeConstraint( y_min_number,BT_TRUE ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_REMOVE_FROM_ACTIVESET_FAILED ); y[nV+y_min_number] = 0.0; } } else { /* no constraint/bound can be removed => QP is infeasible! */ infeasible = BT_TRUE; return THROWERROR( RET_ENSURELI_FAILED_NOINDEX ); } return getGlobalMessageHandler( )->throwInfo( RET_LI_RESOLVED,0,__FUNCTION__,__FILE__,__LINE__,VS_HIDDEN ); } /* * r e m o v e C o n s t r a i n t */ returnValue QProblem::removeConstraint( int number, BooleanType updateCholesky ) { int i, j, ii, jj; /* consistency check */ if ( ( getStatus( ) == QPS_NOTINITIALISED ) || ( getStatus( ) == QPS_AUXILIARYQPSOLVED ) || ( getStatus( ) == QPS_HOMOTOPYQPSOLVED ) || ( getStatus( ) == QPS_SOLVED ) ) { return THROWERROR( RET_UNKNOWN_BUG ); } /* some definitions */ int nFR = getNFR( ); int nAC = getNAC( ); int nZ = getNZ( ); int tcol = sizeT - nAC; int number_idx = constraints.getActive( )->getIndex( number ); /* consistency checks */ if ( constraints.getStatus( number ) == ST_INACTIVE ) return THROWERROR( RET_CONSTRAINT_NOT_ACTIVE ); if ( ( number_idx < 0 ) || ( number_idx >= nAC ) ) return THROWERROR( RET_CONSTRAINT_NOT_ACTIVE ); int FR_idx[NVMAX]; if ( bounds.getFree( )->getNumberArray( FR_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_REMOVECONSTRAINT_FAILED ); /* I) REMOVE th ROW FROM T, * i.e. shift rows number+1 through nAC upwards (instead of the actual * constraint number its corresponding index within matrix A is used). */ if ( number_idx < nAC-1 ) { for( i=(number_idx+1); i=0; --j ) { computeGivens( T[(nAC-2-j)*NVMAX + tcol+1+j],T[(nAC-2-j)*NVMAX + tcol+j], T[(nAC-2-j)*NVMAX + tcol+1+j],T[(nAC-2-j)*NVMAX + tcol+j],c,s ); for( i=(nAC-j-1); i<(nAC-1); ++i ) applyGivens( c,s,T[i*NVMAX + tcol+1+j],T[i*NVMAX + tcol+j], T[i*NVMAX + tcol+1+j],T[i*NVMAX + tcol+j] ); for( i=0; i 0 ) { real_t ZHz[NVMAX]; for ( i=0; i 0.0 ) R[nZ*NVMAX + nZ] = sqrt( rho2 ); else { hessianType = HST_SEMIDEF; return THROWERROR( RET_HESSIAN_NOT_SPD ); } } /* IV) UPDATE INDICES */ if ( constraints.moveActiveToInactive( number ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_REMOVECONSTRAINT_FAILED ); return SUCCESSFUL_RETURN; } /* * r e m o v e B o u n d */ returnValue QProblem::removeBound( int number, BooleanType updateCholesky ) { int i, j, ii, jj; /* consistency checks */ if ( bounds.getStatus( number ) == ST_INACTIVE ) return THROWERROR( RET_BOUND_NOT_ACTIVE ); if ( ( getStatus( ) == QPS_NOTINITIALISED ) || ( getStatus( ) == QPS_AUXILIARYQPSOLVED ) || ( getStatus( ) == QPS_HOMOTOPYQPSOLVED ) || ( getStatus( ) == QPS_SOLVED ) ) { return THROWERROR( RET_UNKNOWN_BUG ); } /* some definitions */ int nFR = getNFR( ); int nAC = getNAC( ); int nZ = getNZ( ); int tcol = sizeT - nAC; /* I) UPDATE INDICES */ if ( bounds.moveFixedToFree( number ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_REMOVEBOUND_FAILED ); int FR_idx[NVMAX]; if ( bounds.getFree( )->getNumberArray( FR_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_REMOVEBOUND_FAILED ); /* I) APPEND th UNITY VECOTR TO Q. */ int nnFRp1 = FR_idx[nFR]; for( i=0; i 0 ) { /* store new column a in a temporary vector instead of shifting T one column to the left and appending a */ int AC_idx[NCMAX_ALLOC]; if ( constraints.getActive( )->getNumberArray( AC_idx ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_REMOVEBOUND_FAILED ); real_t tmp[NCMAX_ALLOC]; for( i=0; i=0; --j ) { computeGivens( tmp[nAC-1-j],T[(nAC-1-j)*NVMAX + tcol+j],T[(nAC-1-j)*NVMAX + tcol+j],tmp[nAC-1-j],c,s ); for( i=(nAC-j); i 0 ) { real_t Hz[NVMAX]; for( i=0; i 0 ) { real_t r[NVMAX]; real_t rhs[NVMAX]; for( i=0; i 0.0 ) R[nZ*NVMAX + nZ] = sqrt( rho2 ); else { hessianType = HST_SEMIDEF; return THROWERROR( RET_HESSIAN_NOT_SPD ); } } return SUCCESSFUL_RETURN; } /* * b a c k s o l v e R (CODE DUPLICATE OF QProblemB CLASS!!!) */ returnValue QProblem::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 DUPLICATE OF QProblemB CLASS!!!) */ returnValue QProblem::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; } /* * b a c k s o l v e T */ returnValue QProblem::backsolveT( const real_t* const b, BooleanType transposed, real_t* const a ) { int i, j; int nT = getNAC( ); int tcol = sizeT - nT; real_t sum; /* nothing to do */ if ( nT <= 0 ) return SUCCESSFUL_RETURN; /* Solve Ta = b, where T might be transposed. */ if ( transposed == BT_FALSE ) { /* solve Ta = b */ for( i=0; i ZERO ) a[nT-1-i] = sum / T[i*NVMAX + sizeT-1-i]; else return THROWERROR( RET_DIV_BY_ZERO ); } } else { /* solve T^T*a = b */ for( i=0; i ZERO ) a[nT-1-i] = sum / T[(nT-1-i)*NVMAX + tcol+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 QProblem::hotstart_determineDataShift( const int* const FX_idx, const int* const AC_idx, const real_t* const g_new, const real_t* const lbA_new, const real_t* const ubA_new, const real_t* const lb_new, const real_t* const ub_new, real_t* const delta_g, real_t* const delta_lbA, real_t* const delta_ubA, real_t* const delta_lb, real_t* const delta_ub, BooleanType& Delta_bC_isZero, BooleanType& Delta_bB_isZero ) { int i, ii; int nC = getNC( ); int nAC = getNAC( ); /* I) DETERMINE DATA SHIFT FOR BOUNDS */ QProblemB::hotstart_determineDataShift( FX_idx,g_new,lb_new,ub_new, delta_g,delta_lb,delta_ub, Delta_bB_isZero ); /* II) DETERMINE DATA SHIFT FOR CONSTRAINTS */ /* 1) Calculate shift directions. */ for( i=0; i EPS ) || ( getAbs( delta_ubA[ii] ) > EPS ) ) { Delta_bC_isZero = BT_FALSE; break; } } return SUCCESSFUL_RETURN; } /* * h o t s t a r t _ d e t e r m i n e S t e p D i r e c t i o n */ returnValue QProblem::hotstart_determineStepDirection( const int* const FR_idx, const int* const FX_idx, const int* const AC_idx, const real_t* const delta_g, const real_t* const delta_lbA, const real_t* const delta_ubA, const real_t* const delta_lb, const real_t* const delta_ub, BooleanType Delta_bC_isZero, BooleanType Delta_bB_isZero, real_t* const delta_xFX, real_t* const delta_xFR, real_t* const delta_yAC, real_t* const delta_yFX ) { int i, j, ii, jj; int nFR = getNFR( ); int nFX = getNFX( ); int nAC = getNAC( ); int nZ = getNZ( ); /* initialise auxiliary vectors */ real_t HMX_delta_xFX[NVMAX]; real_t YFR_delta_xFRy[NVMAX]; real_t ZFR_delta_xFRz[NVMAX]; real_t HFR_YFR_delta_xFRy[NVMAX]; for( i=0; i 0 ) { for( i=0; i 0 ) { /* 1) Determine delta_xFRy. */ if ( nAC > 0 ) { if ( ( Delta_bC_isZero == BT_TRUE ) && ( Delta_bB_isZero == BT_TRUE ) ) { for( i=0; i 0 ) { for( i=0; i 0 ) { if ( ( Delta_bC_isZero == BT_FALSE ) || ( Delta_bB_isZero == BT_FALSE ) ) { for( i=0; i 0 ) { /* auxiliary variable */ real_t delta_xFRz_TMP[NVMAX]; real_t delta_xFRz_RHS[NVMAX]; if ( ( nAC > 0 ) && ( nFX > 0 ) && ( Delta_bB_isZero == BT_FALSE ) ) { for( j=0; j 0 ) /* => Delta_bB_isZero == BT_TRUE, as BT_FALSE would imply nFX>0 */ { for( j=0; j 0 ) /* => ( nFR = nZ + nAC > 0 ) */ { /* auxiliary variables */ real_t delta_yAC_TMP[NCMAX_ALLOC]; for( i=0; i 0 ) { for( i=0; i 0 ) { if ( Delta_bB_isZero == BT_FALSE ) { for( i=0; i 0 ) { for( i=0; i 0.0 ) maxStepLength[nV+ii] = y[nV+ii] / ( -delta_yAC[i] ); else maxStepLength[nV+ii] = 0.0; } } else { /* active upper constraints' bounds */ if ( delta_yAC[i] > ZERO ) { if ( y[nV+ii] < 0.0 ) maxStepLength[nV+ii] = y[nV+ii] / ( -delta_yAC[i] ); else maxStepLength[nV+ii] = 0.0; } } } } /* 2) Ensure that active dual bounds remain valid * (ignoring implicitly fixed variables). */ for( i=0; i 0.0 ) maxStepLength[ii] = y[ii] / ( -delta_yFX[i] ); else maxStepLength[ii] = 0.0; } } else { /* active upper bounds */ if ( delta_yFX[i] > ZERO ) { if ( y[ii] < 0.0 ) maxStepLength[ii] = y[ii] / ( -delta_yFX[i] ); else maxStepLength[ii] = 0.0; } } } } /* II) DETERMINE MAXIMUM PRIMAL STEPLENGTH */ /* 1) Ensure that inactive constraints' bounds remain valid * (ignoring unbounded constraints). */ real_t delta_x[NVMAX]; for( j=0; j delta_Ax[ii] ) { if ( Ax[ii] > lbA[ii] ) maxStepLength[nV+ii] = ( Ax[ii] - lbA[ii] ) / ( delta_lbA[ii] - delta_Ax[ii] ); else maxStepLength[nV+ii] = 0.0; } } /* inactive upper constraints' bounds */ if ( constraints.isNoUpper( ) == BT_FALSE ) { if ( delta_ubA[ii] < delta_Ax[ii] ) { if ( Ax[ii] < ubA[ii] ) maxStepLength[nV+nC+nV+ii] = ( Ax[ii] - ubA[ii] ) / ( delta_ubA[ii] - delta_Ax[ii] ); else maxStepLength[nV+nC+nV+ii] = 0.0; } } } } /* 2) Ensure that inactive bounds remain valid * (ignoring unbounded variables). */ /* inactive lower bounds */ if ( bounds.isNoLower( ) == BT_FALSE ) { for( i=0; i delta_xFR[i] ) { if ( x[ii] > lb[ii] ) maxStepLength[ii] = ( x[ii] - lb[ii] ) / ( delta_lb[ii] - delta_xFR[i] ); else maxStepLength[ii] = 0.0; } } } /* inactive upper bounds */ if ( bounds.isNoUpper( ) == BT_FALSE ) { for( i=0; i EPS ) cyclingManager.clearCyclingData( ); /* V) SET MAXIMUM HOMOTOPY STEPLENGTH */ tau = tau_new; #ifdef PC_DEBUG if ( printlevel == PL_HIGH ) { char messageString[80]; if ( BC_status == ST_UNDEFINED ) sprintf( messageString,"Stepsize is %.6e!",tau ); else sprintf( messageString,"Stepsize is %.6e! (BC_idx = %d, BC_isBound = %d, BC_status = %d)",tau,BC_idx,BC_isBound,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 QProblem::hotstart_performStep( const int* const FR_idx, const int* const FX_idx, const int* const AC_idx, const int* const IAC_idx, const real_t* const delta_g, const real_t* const delta_lbA, const real_t* const delta_ubA, 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_yAC, const real_t* const delta_yFX, const real_t* const delta_Ax, int BC_idx, SubjectToStatus BC_status, BooleanType BC_isBound ) { int i, j, ii; int nV = getNV( ); int nC = getNC( ); int nFR = getNFR( ); int nFX = getNFX( ); int nAC = getNAC( ); int nIAC = getNIAC( ); /* I) CHECK (CONSTRAINTS') BOUNDS' CONSISTENCY */ if ( areBoundsConsistent( delta_lb,delta_ub,delta_lbA,delta_ubA ) == 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: if ( BC_isBound == BT_TRUE ) { #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; } else { #ifdef PC_DEBUG sprintf( messageString,"constraint no. %d.", BC_idx ); getGlobalMessageHandler( )->throwInfo( RET_REMOVE_FROM_ACTIVESET,messageString,__FUNCTION__,__FILE__,__LINE__,visibilityStatus ); #endif if ( removeConstraint( BC_idx,BT_TRUE ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_REMOVE_FROM_ACTIVESET_FAILED ); y[nV+BC_idx] = 0.0; } break; /* Add one variable to active set. */ default: if ( BC_isBound == BT_TRUE ) { #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 ); } else { #ifdef PC_DEBUG if ( BC_status == ST_LOWER ) sprintf( messageString,"lower constraint's bound no. %d.", BC_idx ); else sprintf( messageString,"upper constraint's bound no. %d.", BC_idx ); getGlobalMessageHandler( )->throwInfo( RET_ADD_TO_ACTIVESET,messageString,__FUNCTION__,__FILE__,__LINE__,visibilityStatus ); #endif if ( addConstraint( BC_idx,BC_status,BT_TRUE ) != SUCCESSFUL_RETURN ) return THROWERROR( RET_ADD_TO_ACTIVESET_FAILED ); } break; } return SUCCESSFUL_RETURN; } /* * a r e B o u n d s C o n s i s t e n t */ BooleanType QProblem::areBoundsConsistent( const real_t* const delta_lb, const real_t* const delta_ub, const real_t* const delta_lbA, const real_t* const delta_ubA ) const { int i; /* 1) Check bounds' consistency. */ if ( QProblemB::areBoundsConsistent( delta_lb,delta_ub ) == BT_FALSE ) return BT_FALSE; /* 2) Check constraints' consistency, i.e. * 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 ubA[i] - BOUNDTOL ) && ( delta_lbA[i] > delta_ubA[i] + EPS ) ) return BT_FALSE; return BT_TRUE; } /* * s e t u p Q P d a t a */ returnValue QProblem::setupQPdata( const real_t* const _H, const real_t* const _R, const real_t* const _g, const real_t* const _A, const real_t* const _lb, const real_t* const _ub, const real_t* const _lbA, const real_t* const _ubA ) { int i, j; int nV = getNV( ); int nC = getNC( ); /* 1) Load Hessian matrix as well as lower and upper bounds vectors. */ if (QProblemB::setupQPdata(_H, _R, _g, _lb, _ub) != SUCCESSFUL_RETURN) return THROWERROR( RET_INVALID_ARGUMENTS ); /* 2) Load constraint matrix. */ if ( ( nC > 0 ) && ( _A == 0 ) ) return THROWERROR( RET_INVALID_ARGUMENTS ); if ( nC > 0 ) { for( i=0; igetNumberArray( AC_idx ); /* 1) check for Hx + g - [yFX yAC]*[Id A]' = 0. */ for( i=0; i maxKKTviolation ) maxKKTviolation = getAbs( tmp ); } /* 2) Check for [lb lbA] <= [Id A]*x <= [ub ubA]. */ /* lbA <= Ax <= ubA */ for( i=0; i maxKKTviolation ) maxKKTviolation = lbA[i] - Ax[i]; if ( Ax[i] - ubA[i] > maxKKTviolation ) maxKKTviolation = Ax[i] - ubA[i]; } /* 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. */ /* bounds */ for( i=0; i maxKKTviolation ) maxKKTviolation = -y[i]; if ( getAbs( x[i] - lb[i] ) > maxKKTviolation ) maxKKTviolation = getAbs( x[i] - lb[i] ); break; case ST_UPPER: if ( y[i] > maxKKTviolation ) maxKKTviolation = y[i]; if ( getAbs( ub[i] - x[i] ) > maxKKTviolation ) maxKKTviolation = getAbs( ub[i] - x[i] ); break; default: /* inactive */ if ( getAbs( y[i] ) > maxKKTviolation ) maxKKTviolation = getAbs( y[i] ); break; } } /* constraints */ for( i=0; i maxKKTviolation ) maxKKTviolation = -y[nV+i]; if ( getAbs( Ax[i] - lbA[i] ) > maxKKTviolation ) maxKKTviolation = getAbs( Ax[i] - lbA[i] ); break; case ST_UPPER: if ( y[nV+i] > maxKKTviolation ) maxKKTviolation = y[nV+i]; if ( getAbs( ubA[i] - Ax[i] ) > maxKKTviolation ) maxKKTviolation = getAbs( ubA[i] - Ax[i] ); break; default: /* inactive */ if ( getAbs( y[nV+i] ) > maxKKTviolation ) maxKKTviolation = getAbs( y[nV+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 */