QProblemB.cpp
Go to the documentation of this file.
00001 /*
00002  *      This file is part of qpOASES.
00003  *
00004  *      qpOASES -- An Implementation of the Online Active Set Strategy.
00005  *      Copyright (C) 2007-2008 by Hans Joachim Ferreau et al. All rights reserved.
00006  *
00007  *      qpOASES is free software; you can redistribute it and/or
00008  *      modify it under the terms of the GNU Lesser General Public
00009  *      License as published by the Free Software Foundation; either
00010  *      version 2.1 of the License, or (at your option) any later version.
00011  *
00012  *      qpOASES is distributed in the hope that it will be useful,
00013  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  *      Lesser General Public License for more details.
00016  *
00017  *      You should have received a copy of the GNU Lesser General Public
00018  *      License along with qpOASES; if not, write to the Free Software
00019  *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00020  *
00021  */
00022 
00023 
00035 #include <QProblemB.hpp>
00036 
00037 #include <stdio.h>
00038 
00039 void printmatrix(char *name, double *A, int m, int n) {
00040   int i, j;
00041 
00042   printf("%s = [...\n", name);
00043   for (i = 0; i < m; i++) {
00044     for (j = 0; j < n; j++)
00045         printf("  % 9.4f", A[i*n+j]);
00046     printf(",\n");
00047   }
00048   printf("];\n");
00049 }
00050 
00051 
00052 
00053 /*****************************************************************************
00054  *  P U B L I C                                                              *
00055  *****************************************************************************/
00056 
00057 
00058 /*
00059  *      Q P r o b l e m B
00060  */
00061 QProblemB::QProblemB( )
00062 {
00063         /* reset global message handler */
00064         getGlobalMessageHandler( )->reset( );
00065 
00066         bounds.init( 0 );
00067 
00068         tau = 0.0;
00069 
00070         hessianType = HST_POSDEF_NULLSPACE; /* Hessian is assumed to be positive definite by default */
00071         infeasible = BT_FALSE;
00072         unbounded = BT_FALSE;
00073 
00074         status = QPS_NOTINITIALISED;
00075 
00076         #ifdef PC_DEBUG
00077         printlevel = PL_MEDIUM;
00078         setPrintLevel( PL_MEDIUM );
00079         #else
00080         printlevel = QPOASES_PRINTLEVEL;
00081         #endif
00082 
00083         count = 0;
00084 }
00085 
00086 
00087 /*
00088  *      Q P r o b l e m B
00089  */
00090 QProblemB::QProblemB( int _nV )
00091 {
00092         /* consistency check */
00093         if ( _nV <= 0 )
00094         {
00095                 _nV = 1;
00096                 THROWERROR( RET_INVALID_ARGUMENTS );
00097         }
00098 
00099         /* reset global message handler */
00100         getGlobalMessageHandler( )->reset( );
00101 
00102         bounds.init( _nV );
00103 
00104         tau = 0.0;
00105 
00106         hessianType = HST_POSDEF_NULLSPACE; /* Hessian is assumed to be positive definite by default */
00107         infeasible = BT_FALSE;
00108         unbounded = BT_FALSE;
00109 
00110         status = QPS_NOTINITIALISED;
00111 
00112         #ifdef PC_DEBUG
00113         printlevel = PL_MEDIUM;
00114         setPrintLevel( PL_MEDIUM );
00115         #else
00116         printlevel = QPOASES_PRINTLEVEL;
00117         #endif
00118 
00119         count = 0;
00120 }
00121 
00122 
00123 /*
00124  *      Q P r o b l e m B
00125  */
00126 QProblemB::QProblemB( const QProblemB& rhs )
00127 {
00128         int i, j;
00129 
00130         int _nV = rhs.bounds.getNV( );
00131 
00132         for( i=0; i<_nV; ++i )
00133                 for( j=0; j<_nV; ++j )
00134                         H[i*NVMAX + j] = rhs.H[i*NVMAX + j];
00135 
00136         for( i=0; i<_nV; ++i )
00137                 g[i] = rhs.g[i];
00138 
00139         for( i=0; i<_nV; ++i )
00140                 lb[i] = rhs.lb[i];
00141 
00142         for( i=0; i<_nV; ++i )
00143                 ub[i] = rhs.ub[i];
00144 
00145 
00146         bounds = rhs.bounds;
00147 
00148         for( i=0; i<_nV; ++i )
00149                 for( j=0; j<_nV; ++j )
00150                         R[i*NVMAX + j] = rhs.R[i*NVMAX + j];
00151 
00152         for( i=0; i<_nV; ++i )
00153                 x[i] = rhs.x[i];
00154 
00155         for( i=0; i<_nV; ++i )
00156                 y[i] = rhs.y[i];
00157 
00158         tau = rhs.tau;
00159 
00160         hessianType = rhs.hessianType;
00161         infeasible = rhs.infeasible;
00162         unbounded = rhs.unbounded;
00163 
00164         status = rhs.status;
00165 
00166         printlevel = rhs.printlevel;
00167 
00168         count = rhs.count;
00169 }
00170 
00171 
00172 /*
00173  *      ~ Q P r o b l e m B
00174  */
00175 QProblemB::~QProblemB( )
00176 {
00177 }
00178 
00179 
00180 /*
00181  *      o p e r a t o r =
00182  */
00183 QProblemB& QProblemB::operator=( const QProblemB& rhs )
00184 {
00185         int i, j;
00186 
00187         if ( this != &rhs )
00188         {
00189                 int _nV = rhs.bounds.getNV( );
00190 
00191                 for( i=0; i<_nV; ++i )
00192                         for( j=0; j<_nV; ++j )
00193                                 H[i*NVMAX + j] = rhs.H[i*NVMAX + j];
00194 
00195                 for( i=0; i<_nV; ++i )
00196                         g[i] = rhs.g[i];
00197 
00198                 for( i=0; i<_nV; ++i )
00199                         lb[i] = rhs.lb[i];
00200 
00201                 for( i=0; i<_nV; ++i )
00202                         ub[i] = rhs.ub[i];
00203 
00204                 bounds = rhs.bounds;
00205 
00206                 for( i=0; i<_nV; ++i )
00207                         for( j=0; j<_nV; ++j )
00208                                 R[i*NVMAX + j] = rhs.R[i*NVMAX + j];
00209 
00210 
00211                 for( i=0; i<_nV; ++i )
00212                         x[i] = rhs.x[i];
00213 
00214                 for( i=0; i<_nV; ++i )
00215                         y[i] = rhs.y[i];
00216 
00217                 tau = rhs.tau;
00218 
00219                 hessianType = rhs.hessianType;
00220                 infeasible = rhs.infeasible;
00221                 unbounded = rhs.unbounded;
00222 
00223                 status = rhs.status;
00224 
00225                 printlevel = rhs.printlevel;
00226                 setPrintLevel( rhs.printlevel );
00227 
00228                 count = rhs.count;
00229         }
00230 
00231         return *this;
00232 }
00233 
00234 
00235 /*
00236  *      r e s e t
00237  */
00238 returnValue QProblemB::reset( )
00239 {
00240         int i, j;
00241         int nV = getNV( );
00242 
00243 
00244         /* 1) Reset bounds. */
00245         bounds.init( nV );
00246 
00247         /* 2) Reset Cholesky decomposition. */
00248         for( i=0; i<nV; ++i )
00249                 for( j=0; j<nV; ++j )
00250                         R[i*NVMAX + j] = 0.0;
00251 
00252         /* 3) Reset steplength and status flags. */
00253         tau = 0.0;
00254 
00255         hessianType = HST_POSDEF_NULLSPACE; /* Hessian is assumed to be positive definite by default */
00256         infeasible = BT_FALSE;
00257         unbounded = BT_FALSE;
00258 
00259         status = QPS_NOTINITIALISED;
00260 
00261         return SUCCESSFUL_RETURN;
00262 }
00263 
00264 
00265 /*
00266  *      i n i t
00267  */
00268 returnValue QProblemB::init(    const real_t* const _H, const real_t* const _g,
00269                                                                 const real_t* const _lb, const real_t* const _ub,
00270                                                                 int& nWSR, const real_t* const yOpt, real_t* const cputime
00271                                                                 )
00272 {
00273         /* 1) Setup QP data. */
00274         if ( setupQPdata( _H,_g,_lb,_ub ) != SUCCESSFUL_RETURN )
00275                 return THROWERROR( RET_INVALID_ARGUMENTS );
00276 
00277         /* 2) Call to main initialisation routine (without any additional information). */
00278         return solveInitialQP( 0,yOpt,0, nWSR,cputime );
00279 }
00280 
00281 
00282 /*
00283  *      h o t s t a r t
00284  */
00285 returnValue QProblemB::hotstart(        const real_t* const g_new, const real_t* const lb_new, const real_t* const ub_new,
00286                                                                         int& nWSR, real_t* const cputime
00287                                                                         )
00288 {
00289         int l;
00290 
00291         /* consistency check */
00292         if ( ( getStatus( ) == QPS_NOTINITIALISED )       ||
00293                  ( getStatus( ) == QPS_PREPARINGAUXILIARYQP ) ||
00294                  ( getStatus( ) == QPS_PERFORMINGHOMOTOPY )   )
00295         {
00296                 return THROWERROR( RET_HOTSTART_FAILED_AS_QP_NOT_INITIALISED );
00297         }
00298 
00299         /* start runtime measurement */
00300         real_t starttime = 0.0;
00301         if ( cputime != 0 )
00302                 starttime = getCPUtime( );
00303 
00304 
00305         /* I) PREPARATIONS */
00306         /* 1) Reset status flags and increase QP counter. */
00307         infeasible = BT_FALSE;
00308         unbounded = BT_FALSE;
00309 
00310         ++count;
00311 
00312         /* 2) Allocate delta vectors of gradient and bounds. */
00313         returnValue returnvalue;
00314         BooleanType Delta_bB_isZero;
00315 
00316         int FR_idx[NVMAX];
00317         int FX_idx[NVMAX];
00318 
00319         real_t delta_g[NVMAX];
00320         real_t delta_lb[NVMAX];
00321         real_t delta_ub[NVMAX];
00322 
00323         real_t delta_xFR[NVMAX];
00324         real_t delta_xFX[NVMAX];
00325         real_t delta_yFX[NVMAX];
00326 
00327         int BC_idx;
00328         SubjectToStatus BC_status;
00329 
00330         #ifdef PC_DEBUG
00331         char messageString[80];
00332         #endif
00333 
00334         /* II) MAIN HOMOTOPY LOOP */
00335         for( l=0; l<nWSR; ++l )
00336         {
00337                 status = QPS_PERFORMINGHOMOTOPY;
00338 
00339                 if ( printlevel == PL_HIGH )
00340                 {
00341                         #ifdef PC_DEBUG
00342                         sprintf( messageString,"%d ...",l );
00343                         getGlobalMessageHandler( )->throwInfo( RET_ITERATION_STARTED,messageString,__FUNCTION__,__FILE__,__LINE__,VS_VISIBLE );
00344                         #endif
00345                 }
00346 
00347                 /* 1) Setup index arrays. */
00348                 if ( bounds.getFree( )->getNumberArray( FR_idx ) != SUCCESSFUL_RETURN )
00349                         return THROWERROR( RET_HOTSTART_FAILED );
00350 
00351                 if ( bounds.getFixed( )->getNumberArray( FX_idx ) != SUCCESSFUL_RETURN )
00352                         return THROWERROR( RET_HOTSTART_FAILED );
00353 
00354                 /* 2) Initialise shift direction of the gradient and the bounds. */
00355                 returnvalue = hotstart_determineDataShift(  FX_idx,
00356                                                                                                         g_new,lb_new,ub_new,
00357                                                                                                         delta_g,delta_lb,delta_ub,
00358                                                                                                         Delta_bB_isZero
00359                                                                                                         );
00360                 if ( returnvalue != SUCCESSFUL_RETURN )
00361                 {
00362                         nWSR = l;
00363                         THROWERROR( RET_SHIFT_DETERMINATION_FAILED );
00364                         return returnvalue;
00365                 }
00366 
00367                 /* 3) Determination of step direction of X and Y. */
00368                 returnvalue = hotstart_determineStepDirection(  FR_idx,FX_idx,
00369                                                                                                                 delta_g,delta_lb,delta_ub,
00370                                                                                                                 Delta_bB_isZero,
00371                                                                                                                 delta_xFX,delta_xFR,delta_yFX
00372                                                                                                                 );
00373                 if ( returnvalue != SUCCESSFUL_RETURN )
00374                 {
00375                         nWSR = l;
00376                         THROWERROR( RET_STEPDIRECTION_DETERMINATION_FAILED );
00377                         return returnvalue;
00378                 }
00379 
00380 
00381                 /* 4) Determination of step length TAU. */
00382                 returnvalue = hotstart_determineStepLength(     FR_idx,FX_idx,
00383                                                                                                         delta_lb,delta_ub,
00384                                                                                                         delta_xFR,delta_yFX,
00385                                                                                                         BC_idx,BC_status );
00386                 if ( returnvalue != SUCCESSFUL_RETURN )
00387                 {
00388                         nWSR = l;
00389                         THROWERROR( RET_STEPLENGTH_DETERMINATION_FAILED );
00390                         return returnvalue;
00391                 }
00392 
00393                 /* 5) Realisation of the homotopy step. */
00394                 returnvalue = hotstart_performStep(     FR_idx,FX_idx,
00395                                                                                         delta_g,delta_lb,delta_ub,
00396                                                                                         delta_xFX,delta_xFR,delta_yFX,
00397                                                                                         BC_idx,BC_status
00398                                                                                         );
00399 
00400 
00401                 if ( returnvalue != SUCCESSFUL_RETURN )
00402                 {
00403                         nWSR = l;
00404 
00405                         /* stop runtime measurement */
00406                         if ( cputime != 0 )
00407                                 *cputime = getCPUtime( ) - starttime;
00408 
00409                         /* optimal solution found? */
00410                         if ( returnvalue == RET_OPTIMAL_SOLUTION_FOUND )
00411                         {
00412                                 status = QPS_SOLVED;
00413 
00414                                 if ( printlevel == PL_HIGH )
00415                                         THROWINFO( RET_OPTIMAL_SOLUTION_FOUND );
00416 
00417                                 #ifdef PC_DEBUG
00418                                 if ( printIteration( l,BC_idx,BC_status ) != SUCCESSFUL_RETURN )
00419                                         THROWERROR( RET_PRINT_ITERATION_FAILED ); /* do not pass this as return value! */
00420                                 #endif
00421 
00422                                 /* check KKT optimality conditions */
00423                                 return checkKKTconditions( );
00424                         }
00425                         else
00426                         {
00427                                 /* checks for infeasibility... */
00428                                 if ( infeasible == BT_TRUE )
00429                                 {
00430                                         status = QPS_HOMOTOPYQPSOLVED;
00431                                         return THROWERROR( RET_HOTSTART_STOPPED_INFEASIBILITY );
00432                                 }
00433 
00434                                 /* ...unboundedness... */
00435                                 if ( unbounded == BT_TRUE ) /* not necessary since objective function convex! */
00436                                         return THROWERROR( RET_HOTSTART_STOPPED_UNBOUNDEDNESS );
00437 
00438                                 /* ... and throw unspecific error otherwise */
00439                                 THROWERROR( RET_HOMOTOPY_STEP_FAILED );
00440                                 return returnvalue;
00441                         }
00442                 }
00443 
00444                 /* 6) Output information of successful QP iteration. */
00445                 status = QPS_HOMOTOPYQPSOLVED;
00446 
00447                 #ifdef PC_DEBUG
00448                 if ( printIteration( l,BC_idx,BC_status ) != SUCCESSFUL_RETURN )
00449                         THROWERROR( RET_PRINT_ITERATION_FAILED ); /* do not pass this as return value! */
00450                 #endif
00451         }
00452 
00453 
00454         /* stop runtime measurement */
00455         if ( cputime != 0 )
00456                 *cputime = getCPUtime( ) - starttime;
00457 
00458 
00459         /* if programm gets to here, output information that QP could not be solved
00460          * within the given maximum numbers of working set changes */
00461         if ( printlevel == PL_HIGH )
00462         {
00463                 #ifdef PC_DEBUG
00464                 sprintf( messageString,"(nWSR = %d)",nWSR );
00465                 return getGlobalMessageHandler( )->throwWarning( RET_MAX_NWSR_REACHED,messageString,__FUNCTION__,__FILE__,__LINE__,VS_VISIBLE );
00466                 #endif
00467         }
00468 
00469         /* Finally check KKT optimality conditions. */
00470         returnValue returnvalueKKTcheck = checkKKTconditions( );
00471 
00472         if ( returnvalueKKTcheck != SUCCESSFUL_RETURN )
00473                 return returnvalueKKTcheck;
00474         else
00475                 return RET_MAX_NWSR_REACHED;
00476 }
00477 
00478 
00479 /*
00480  *      g e t N Z
00481  */
00482 int QProblemB::getNZ( )
00483 {
00484         /* if no constraints are present: nZ=nFR */
00485         return bounds.getFree( )->getLength( );
00486 }
00487 
00488 
00489 /*
00490  *      g e t O b j V a l
00491  */
00492 real_t QProblemB::getObjVal( ) const
00493 {
00494         real_t objVal;
00495 
00496         /* calculated optimal objective function value
00497          * only if current QP has been solved */
00498         if ( ( getStatus( ) == QPS_AUXILIARYQPSOLVED ) ||
00499                  ( getStatus( ) == QPS_HOMOTOPYQPSOLVED )  ||
00500                  ( getStatus( ) == QPS_SOLVED ) )
00501         {
00502                 objVal = getObjVal( x );
00503         }
00504         else
00505         {
00506                 objVal = INFTY;
00507         }
00508 
00509         return objVal;
00510 }
00511 
00512 
00513 /*
00514  *      g e t O b j V a l
00515  */
00516 real_t QProblemB::getObjVal( const real_t* const _x ) const
00517 {
00518         int i, j;
00519         int nV = getNV( );
00520 
00521         real_t obj_tmp = 0.0;
00522 
00523         for( i=0; i<nV; ++i )
00524         {
00525                 obj_tmp += _x[i]*g[i];
00526 
00527                 for( j=0; j<nV; ++j )
00528                         obj_tmp += 0.5*_x[i]*H[i*NVMAX + j]*_x[j];
00529         }
00530 
00531         return obj_tmp;
00532 }
00533 
00534 
00535 /*
00536  *      g e t P r i m a l S o l u t i o n
00537  */
00538 returnValue QProblemB::getPrimalSolution( real_t* const xOpt ) const
00539 {
00540         int i;
00541 
00542         /* return optimal primal solution vector
00543          * only if current QP has been solved */
00544         if ( ( getStatus( ) == QPS_AUXILIARYQPSOLVED ) ||
00545                  ( getStatus( ) == QPS_HOMOTOPYQPSOLVED )  ||
00546                  ( getStatus( ) == QPS_SOLVED ) )
00547         {
00548                 for( i=0; i<getNV( ); ++i )
00549                         xOpt[i] = x[i];
00550 
00551                 return SUCCESSFUL_RETURN;
00552         }
00553         else
00554         {
00555                 return RET_QP_NOT_SOLVED;
00556         }
00557 }
00558 
00559 
00560 /*
00561  *      g e t D u a l S o l u t i o n
00562  */
00563 returnValue QProblemB::getDualSolution( real_t* const yOpt ) const
00564 {
00565         int i;
00566 
00567         /* return optimal dual solution vector
00568          * only if current QP has been solved */
00569         if ( ( getStatus( ) == QPS_AUXILIARYQPSOLVED ) ||
00570                  ( getStatus( ) == QPS_HOMOTOPYQPSOLVED )  ||
00571                  ( getStatus( ) == QPS_SOLVED ) )
00572         {
00573                 for( i=0; i<getNV( ); ++i )
00574                         yOpt[i] = y[i];
00575 
00576                 return SUCCESSFUL_RETURN;
00577         }
00578         else
00579         {
00580                 return RET_QP_NOT_SOLVED;
00581         }
00582 }
00583 
00584 
00585 /*
00586  *      s e t P r i n t L e v e l
00587  */
00588 returnValue QProblemB::setPrintLevel( PrintLevel _printlevel )
00589 {
00590         #ifndef __MATLAB__
00591         if ( ( printlevel >= PL_MEDIUM ) && ( printlevel != _printlevel ) )
00592                 THROWINFO( RET_PRINTLEVEL_CHANGED );
00593         #endif
00594 
00595         printlevel = _printlevel;
00596 
00597         /* update message handler preferences */
00598         switch ( printlevel )
00599         {
00600                 case PL_NONE:
00601                         getGlobalMessageHandler( )->setErrorVisibilityStatus( VS_HIDDEN );
00602                         getGlobalMessageHandler( )->setWarningVisibilityStatus( VS_HIDDEN );
00603                         getGlobalMessageHandler( )->setInfoVisibilityStatus( VS_HIDDEN );
00604                         break;
00605 
00606                 case PL_LOW:
00607                         getGlobalMessageHandler( )->setErrorVisibilityStatus( VS_VISIBLE );
00608                         getGlobalMessageHandler( )->setWarningVisibilityStatus( VS_HIDDEN );
00609                         getGlobalMessageHandler( )->setInfoVisibilityStatus( VS_HIDDEN );
00610                         break;
00611 
00612                 default: /* PL_MEDIUM, PL_HIGH */
00613                         getGlobalMessageHandler( )->setErrorVisibilityStatus( VS_VISIBLE );
00614                         getGlobalMessageHandler( )->setWarningVisibilityStatus( VS_VISIBLE );
00615                         getGlobalMessageHandler( )->setInfoVisibilityStatus( VS_VISIBLE );
00616                         break;
00617         }
00618 
00619         return SUCCESSFUL_RETURN;
00620 }
00621 
00622 
00623 
00624 /*****************************************************************************
00625  *  P R O T E C T E D                                                        *
00626  *****************************************************************************/
00627 
00628 /*
00629  *      c h e c k F o r I d e n t i t y H e s s i a n
00630  */
00631 returnValue QProblemB::checkForIdentityHessian( )
00632 {
00633         int i, j;
00634         int nV = getNV( );
00635 
00636         /* nothing to do as status flag remains unaltered
00637          * if Hessian differs from identity matrix */
00638         if ( hessianType == HST_IDENTITY )
00639                 return SUCCESSFUL_RETURN;
00640 
00641         /* 1) If Hessian differs from identity matrix,
00642          *    return without changing the internal HessianType. */
00643         for ( i=0; i<nV; ++i )
00644                 if ( getAbs( H[i*NVMAX + i] - 1.0 ) > EPS )
00645                         return SUCCESSFUL_RETURN;
00646 
00647         for ( i=0; i<nV; ++i )
00648         {
00649                 for ( j=0; j<i; ++j )
00650                         if ( ( getAbs( H[i*NVMAX + j] ) > EPS ) || ( getAbs( H[j*NVMAX + i] ) > EPS ) )
00651                                 return SUCCESSFUL_RETURN;
00652         }
00653 
00654         /* 2) If this point is reached, Hessian equals the idetity matrix. */
00655         hessianType = HST_IDENTITY;
00656 
00657         return SUCCESSFUL_RETURN;
00658 }
00659 
00660 
00661 /*
00662  *      s e t u p S u b j e c t T o T y p e
00663  */
00664 returnValue QProblemB::setupSubjectToType( )
00665 {
00666         int i;
00667         int nV = getNV( );
00668 
00669 
00670         /* 1) Check if lower bounds are present. */
00671         bounds.setNoLower( BT_TRUE );
00672         for( i=0; i<nV; ++i )
00673                 if ( lb[i] > -INFTY )
00674                 {
00675                         bounds.setNoLower( BT_FALSE );
00676                         break;
00677                 }
00678 
00679         /* 2) Check if upper bounds are present. */
00680         bounds.setNoUpper( BT_TRUE );
00681         for( i=0; i<nV; ++i )
00682                 if ( ub[i] < INFTY )
00683                 {
00684                         bounds.setNoUpper( BT_FALSE );
00685                         break;
00686                 }
00687 
00688         /* 3) Determine implicitly fixed and unbounded variables. */
00689         int nFV = 0;
00690         int nUV = 0;
00691 
00692         for( i=0; i<nV; ++i )
00693                 if ( ( lb[i] < -INFTY + BOUNDTOL ) && ( ub[i] > INFTY - BOUNDTOL ) )
00694                 {
00695                         bounds.setType( i,ST_UNBOUNDED );
00696                         ++nUV;
00697                 }
00698                 else
00699                 {
00700                         if ( lb[i] > ub[i] - BOUNDTOL )
00701                         {
00702                                 bounds.setType( i,ST_EQUALITY );
00703                                 ++nFV;
00704                         }
00705                         else
00706                         {
00707                                 bounds.setType( i,ST_BOUNDED );
00708                         }
00709                 }
00710 
00711         /* 4) Set dimensions of bounds structure. */
00712         bounds.setNFV( nFV );
00713         bounds.setNUV( nUV );
00714         bounds.setNBV( nV - nFV - nUV );
00715 
00716         return SUCCESSFUL_RETURN;
00717 }
00718 
00719 
00720 /*
00721  *      c h o l e s k y D e c o m p o s i t i o n
00722  */
00723 returnValue QProblemB::setupCholeskyDecomposition( )
00724 {
00725         int i, j, k, ii, jj;
00726         int nV  = getNV( );
00727         int nFR = getNFR( );
00728 
00729         /* 1) Initialises R with all zeros. */
00730         for( i=0; i<nV; ++i )
00731                 for( j=0; j<nV; ++j )
00732                         R[i*NVMAX + j] = 0.0;
00733 
00734         /* 2) Calculate Cholesky decomposition of H (projected to free variables). */
00735         if ( hessianType == HST_IDENTITY )
00736         {
00737                 /* if Hessian is identity, so is its Cholesky factor. */
00738                 for( i=0; i<nFR; ++i )
00739                         R[i*NVMAX + i] = 1.0;
00740         }
00741         else
00742         {
00743                 if ( nFR > 0 )
00744                 {
00745                         int FR_idx[NVMAX];
00746                         if ( bounds.getFree( )->getNumberArray( FR_idx ) != SUCCESSFUL_RETURN )
00747                                 return THROWERROR( RET_INDEXLIST_CORRUPTED );
00748 
00749                         /* R'*R = H */
00750                         real_t sum;
00751 
00752                         for( i=0; i<nFR; ++i )
00753                         {
00754                                 /* j == i */
00755                                 ii = FR_idx[i];
00756                                 sum = H[ii*NVMAX + ii];
00757 
00758                                 for( k=(i-1); k>=0; --k )
00759                                         sum -= R[k*NVMAX + i] * R[k*NVMAX + i];
00760 
00761                                 if ( sum > 0.0 )
00762                                         R[i*NVMAX + i] = sqrt( sum );
00763                                 else
00764                                 {
00765                                         hessianType = HST_SEMIDEF;
00766                                         return THROWERROR( RET_HESSIAN_NOT_SPD );
00767                                 }
00768 
00769                                 /* j > i */
00770                                 for( j=(i+1); j<nFR; ++j )
00771                                 {
00772                                         jj = FR_idx[j];
00773                                         sum = H[jj*NVMAX + ii];
00774 
00775                                         for( k=(i-1); k>=0; --k )
00776                                                 sum -= R[k*NVMAX + i] * R[k*NVMAX + j];
00777 
00778                                         R[i*NVMAX + j] = sum / R[i*NVMAX + i];
00779                                 }
00780                         }
00781                 }
00782         }
00783 
00784         return SUCCESSFUL_RETURN;
00785 }
00786 
00787 
00788 /*
00789  *      s o l v e I n i t i a l Q P
00790  */
00791 returnValue QProblemB::solveInitialQP(  const real_t* const xOpt, const real_t* const yOpt,
00792                                                                                 const Bounds* const guessedBounds,
00793                                                                                 int& nWSR, real_t* const cputime
00794                                                                                 )
00795 {
00796         int i;
00797         int nV = getNV( );
00798 
00799 
00800         /* start runtime measurement */
00801         real_t starttime = 0.0;
00802         if ( cputime != 0 )
00803                 starttime = getCPUtime( );
00804 
00805 
00806         status = QPS_NOTINITIALISED;
00807 
00808         /* I) ANALYSE QP DATA: */
00809         /* 1) Check if Hessian happens to be the identity matrix. */
00810         if ( checkForIdentityHessian( ) != SUCCESSFUL_RETURN )
00811                 return THROWERROR( RET_INIT_FAILED );
00812 
00813         /* 2) Setup type of bounds (i.e. unbounded, implicitly fixed etc.). */
00814         if ( setupSubjectToType( ) != SUCCESSFUL_RETURN )
00815                 return THROWERROR( RET_INIT_FAILED );
00816 
00817         status = QPS_PREPARINGAUXILIARYQP;
00818 
00819 
00820         /* II) SETUP AUXILIARY QP WITH GIVEN OPTIMAL SOLUTION: */
00821         /* 1) Setup bounds data structure. */
00822         if ( bounds.setupAllFree( ) != SUCCESSFUL_RETURN )
00823                 return THROWERROR( RET_INIT_FAILED );
00824 
00825         /* 2) Setup optimal primal/dual solution for auxiliary QP. */
00826         if ( setupAuxiliaryQPsolution( xOpt,yOpt ) != SUCCESSFUL_RETURN )
00827                 return THROWERROR( RET_INIT_FAILED );
00828 
00829         /* 3) Obtain linear independent working set for auxiliary QP. */
00830 
00831         static Bounds auxiliaryBounds;
00832 
00833         auxiliaryBounds.init( nV );
00834 
00835         if ( obtainAuxiliaryWorkingSet( xOpt,yOpt,guessedBounds, &auxiliaryBounds ) != SUCCESSFUL_RETURN )
00836                 return THROWERROR( RET_INIT_FAILED );
00837 
00838         /* 4) Setup working set of auxiliary QP and setup cholesky decomposition. */
00839         if ( setupAuxiliaryWorkingSet( &auxiliaryBounds,BT_TRUE ) != SUCCESSFUL_RETURN )
00840                 return THROWERROR( RET_INIT_FAILED );
00841 
00842         if ( setupCholeskyDecomposition( ) != SUCCESSFUL_RETURN )
00843                 return THROWERROR( RET_INIT_FAILED_CHOLESKY );
00844 
00845         /* 5) Store original QP formulation... */
00846         real_t g_original[NVMAX];
00847         real_t lb_original[NVMAX];
00848         real_t ub_original[NVMAX];
00849 
00850         for( i=0; i<nV; ++i )
00851         {
00852                 g_original[i] = g[i];
00853                 lb_original[i] = lb[i];
00854                 ub_original[i] = ub[i];
00855         }
00856 
00857         /* ... and setup QP data of an auxiliary QP having an optimal solution
00858          * as specified by the user (or xOpt = yOpt = 0, by default). */
00859         if ( setupAuxiliaryQPgradient( ) != SUCCESSFUL_RETURN )
00860                 return THROWERROR( RET_INIT_FAILED );
00861 
00862         if ( setupAuxiliaryQPbounds( BT_TRUE ) != SUCCESSFUL_RETURN )
00863                 return THROWERROR( RET_INIT_FAILED );
00864 
00865         status = QPS_AUXILIARYQPSOLVED;
00866 
00867 
00868         /* III) SOLVE ACTUAL INITIAL QP: */
00869         /* Use hotstart method to find the solution of the original initial QP,... */
00870         returnValue returnvalue = hotstart( g_original,lb_original,ub_original, nWSR,0 );
00871 
00872 
00873         /* ... check for infeasibility and unboundedness... */
00874         if ( isInfeasible( ) == BT_TRUE )
00875                 return THROWERROR( RET_INIT_FAILED_INFEASIBILITY );
00876 
00877         if ( isUnbounded( ) == BT_TRUE )
00878                 return THROWERROR( RET_INIT_FAILED_UNBOUNDEDNESS );
00879 
00880         /* ... and internal errors. */
00881         if ( ( returnvalue != SUCCESSFUL_RETURN ) && ( returnvalue != RET_MAX_NWSR_REACHED )  &&
00882              ( returnvalue != RET_INACCURATE_SOLUTION ) && ( returnvalue != RET_NO_SOLUTION ) )
00883                 return THROWERROR( RET_INIT_FAILED_HOTSTART );
00884 
00885 
00886         /* stop runtime measurement */
00887         if ( cputime != 0 )
00888                 *cputime = getCPUtime( ) - starttime;
00889 
00890         if ( printlevel == PL_HIGH )
00891                 THROWINFO( RET_INIT_SUCCESSFUL );
00892 
00893         return returnvalue;
00894 }
00895 
00896 
00897 /*
00898  *      o b t a i n A u x i l i a r y W o r k i n g S e t
00899  */
00900 returnValue QProblemB::obtainAuxiliaryWorkingSet(       const real_t* const xOpt, const real_t* const yOpt,
00901                                                                                                         const Bounds* const guessedBounds, Bounds* auxiliaryBounds
00902                                                                                                         ) const
00903 {
00904         int i = 0;
00905         int nV = getNV( );
00906 
00907 
00908         /* 1) Ensure that desiredBounds is allocated (and different from guessedBounds). */
00909         if ( ( auxiliaryBounds == 0 ) || ( auxiliaryBounds == guessedBounds ) )
00910                 return THROWERROR( RET_INVALID_ARGUMENTS );
00911 
00912 
00913         /* 2) Setup working set for auxiliary initial QP. */
00914         if ( guessedBounds != 0 )
00915         {
00916                 /* If an initial working set is specific, use it!
00917                  * Moreover, add all implictly fixed variables if specified. */
00918                 for( i=0; i<nV; ++i )
00919                 {
00920                         if ( bounds.getType( i ) == ST_EQUALITY )
00921                         {
00922                                 if ( auxiliaryBounds->setupBound( i,ST_LOWER ) != SUCCESSFUL_RETURN )
00923                                         return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED );
00924                         }
00925                         else
00926                         {
00927                                 if ( auxiliaryBounds->setupBound( i,guessedBounds->getStatus( i ) ) != SUCCESSFUL_RETURN )
00928                                         return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED );
00929                         }
00930                 }
00931         }
00932         else    /* No initial working set specified. */
00933         {
00934                 if ( ( xOpt != 0 ) && ( yOpt == 0 ) )
00935                 {
00936                         /* Obtain initial working set by "clipping". */
00937                         for( i=0; i<nV; ++i )
00938                         {
00939                                 if ( xOpt[i] <= lb[i] + BOUNDTOL )
00940                                 {
00941                                         if ( auxiliaryBounds->setupBound( i,ST_LOWER ) != SUCCESSFUL_RETURN )
00942                                                 return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED );
00943                                         continue;
00944                                 }
00945 
00946                                 if ( xOpt[i] >= ub[i] - BOUNDTOL )
00947                                 {
00948                                         if ( auxiliaryBounds->setupBound( i,ST_UPPER ) != SUCCESSFUL_RETURN )
00949                                                 return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED );
00950                                         continue;
00951                                 }
00952 
00953                                 /* Moreover, add all implictly fixed variables if specified. */
00954                                 if ( bounds.getType( i ) == ST_EQUALITY )
00955                                 {
00956                                         if ( auxiliaryBounds->setupBound( i,ST_LOWER ) != SUCCESSFUL_RETURN )
00957                                                 return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED );
00958                                 }
00959                                 else
00960                                 {
00961                                         if ( auxiliaryBounds->setupBound( i,ST_INACTIVE ) != SUCCESSFUL_RETURN )
00962                                                 return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED );
00963                                 }
00964                         }
00965                 }
00966 
00967                 if ( ( xOpt == 0 ) && ( yOpt != 0 ) )
00968                 {
00969                         /* Obtain initial working set in accordance to sign of dual solution vector. */
00970                         for( i=0; i<nV; ++i )
00971                         {
00972                                 if ( yOpt[i] > ZERO )
00973                                 {
00974                                         if ( auxiliaryBounds->setupBound( i,ST_LOWER ) != SUCCESSFUL_RETURN )
00975                                                 return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED );
00976                                         continue;
00977                                 }
00978 
00979                                 if ( yOpt[i] < -ZERO )
00980                                 {
00981                                         if ( auxiliaryBounds->setupBound( i,ST_UPPER ) != SUCCESSFUL_RETURN )
00982                                                 return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED );
00983                                         continue;
00984                                 }
00985 
00986                                 /* Moreover, add all implictly fixed variables if specified. */
00987                                 if ( bounds.getType( i ) == ST_EQUALITY )
00988                                 {
00989                                         if ( auxiliaryBounds->setupBound( i,ST_LOWER ) != SUCCESSFUL_RETURN )
00990                                                 return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED );
00991                                 }
00992                                 else
00993                                 {
00994                                         if ( auxiliaryBounds->setupBound( i,ST_INACTIVE ) != SUCCESSFUL_RETURN )
00995                                                 return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED );
00996                                 }
00997                         }
00998                 }
00999 
01000                 /* If xOpt and yOpt are null pointer and no initial working is specified,
01001                  * start with empty working set (or implicitly fixed bounds only)
01002                  * for auxiliary QP. */
01003                 if ( ( xOpt == 0 ) && ( yOpt == 0 ) )
01004                 {
01005                         for( i=0; i<nV; ++i )
01006                         {
01007                                 /* Only add all implictly fixed variables if specified. */
01008                                 if ( bounds.getType( i ) == ST_EQUALITY )
01009                                 {
01010                                         if ( auxiliaryBounds->setupBound( i,ST_LOWER ) != SUCCESSFUL_RETURN )
01011                                                 return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED );
01012                                 }
01013                                 else
01014                                 {
01015                                         if ( auxiliaryBounds->setupBound( i,ST_INACTIVE ) != SUCCESSFUL_RETURN )
01016                                                 return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED );
01017                                 }
01018                         }
01019                 }
01020         }
01021 
01022         return SUCCESSFUL_RETURN;
01023 }
01024 
01025 
01026 /*
01027  *      s e t u p A u x i l i a r y W o r k i n g S e t
01028  */
01029 returnValue QProblemB::setupAuxiliaryWorkingSet(        const Bounds* const auxiliaryBounds,
01030                                                                                                         BooleanType setupAfresh
01031                                                                                                         )
01032 {
01033         int i;
01034         int nV = getNV( );
01035 
01036         /* consistency checks */
01037         if ( auxiliaryBounds != 0 )
01038         {
01039                 for( i=0; i<nV; ++i )
01040                         if ( ( bounds.getStatus( i ) == ST_UNDEFINED ) || ( auxiliaryBounds->getStatus( i ) == ST_UNDEFINED ) )
01041                                 return THROWERROR( RET_UNKNOWN_BUG );
01042         }
01043         else
01044         {
01045                 return THROWERROR( RET_INVALID_ARGUMENTS );
01046         }
01047 
01048 
01049         /* I) SETUP CHOLESKY FLAG:
01050          *    Cholesky decomposition shall only be updated if working set
01051          *    shall be updated (i.e. NOT setup afresh!) */
01052         BooleanType updateCholesky;
01053         if ( setupAfresh == BT_TRUE )
01054                 updateCholesky = BT_FALSE;
01055         else
01056                 updateCholesky = BT_TRUE;
01057 
01058 
01059         /* II) REMOVE FORMERLY ACTIVE BOUNDS (IF NECESSARY): */
01060         if ( setupAfresh == BT_FALSE )
01061         {
01062                 /* Remove all active bounds that shall be inactive AND
01063                 *  all active bounds that are active at the wrong bound. */
01064                 for( i=0; i<nV; ++i )
01065                 {
01066                         if ( ( bounds.getStatus( i ) == ST_LOWER ) && ( auxiliaryBounds->getStatus( i ) != ST_LOWER ) )
01067                                 if ( removeBound( i,updateCholesky ) != SUCCESSFUL_RETURN )
01068                                         return THROWERROR( RET_SETUP_WORKINGSET_FAILED );
01069 
01070                         if ( ( bounds.getStatus( i ) == ST_UPPER ) && ( auxiliaryBounds->getStatus( i ) != ST_UPPER ) )
01071                                 if ( removeBound( i,updateCholesky ) != SUCCESSFUL_RETURN )
01072                                         return THROWERROR( RET_SETUP_WORKINGSET_FAILED );
01073                 }
01074         }
01075 
01076 
01077         /* III) ADD NEWLY ACTIVE BOUNDS: */
01078         /*      Add all inactive bounds that shall be active AND
01079          *      all formerly active bounds that have been active at the wrong bound. */
01080         for( i=0; i<nV; ++i )
01081         {
01082                 if ( ( bounds.getStatus( i ) == ST_INACTIVE ) && ( auxiliaryBounds->getStatus( i ) != ST_INACTIVE ) )
01083                 {
01084                         if ( addBound( i,auxiliaryBounds->getStatus( i ),updateCholesky ) != SUCCESSFUL_RETURN )
01085                                 return THROWERROR( RET_SETUP_WORKINGSET_FAILED );
01086                 }
01087         }
01088 
01089         return SUCCESSFUL_RETURN;
01090 }
01091 
01092 
01093 /*
01094  *      s e t u p A u x i l i a r y Q P s o l u t i o n
01095  */
01096 returnValue QProblemB::setupAuxiliaryQPsolution(        const real_t* const xOpt, const real_t* const yOpt
01097                                                                                                         )
01098 {
01099         int i;
01100         int nV = getNV( );
01101 
01102 
01103         /* Setup primal/dual solution vectors for auxiliary initial QP:
01104          * if a null pointer is passed, a zero vector is assigned;
01105          * old solution vector is kept if pointer to internal solution vector is passed. */
01106         if ( xOpt != 0 )
01107         {
01108                 if ( xOpt != x )
01109                         for( i=0; i<nV; ++i )
01110                                 x[i] = xOpt[i];
01111         }
01112         else
01113         {
01114                 for( i=0; i<nV; ++i )
01115                         x[i] = 0.0;
01116         }
01117 
01118         if ( yOpt != 0 )
01119         {
01120                 if ( yOpt != y )
01121                         for( i=0; i<nV; ++i )
01122                                 y[i] = yOpt[i];
01123         }
01124         else
01125         {
01126                 for( i=0; i<nV; ++i )
01127                         y[i] = 0.0;
01128         }
01129 
01130         return SUCCESSFUL_RETURN;
01131 }
01132 
01133 
01134 /*
01135  *      s e t u p A u x i l i a r y Q P g r a d i e n t
01136  */
01137 returnValue QProblemB::setupAuxiliaryQPgradient( )
01138 {
01139         int i, j;
01140         int nV = getNV( );
01141 
01142 
01143         /* Setup gradient vector: g = -H*x + y'*Id. */
01144         for ( i=0; i<nV; ++i )
01145         {
01146                 /* y'*Id */
01147                 g[i] = y[i];
01148 
01149                 /* -H*x */
01150                 for ( j=0; j<nV; ++j )
01151                         g[i] -= H[i*NVMAX + j] * x[j];
01152         }
01153 
01154         return SUCCESSFUL_RETURN;
01155 }
01156 
01157 
01158 /*
01159  *      s e t u p A u x i l i a r y Q P b o u n d s
01160  */
01161 returnValue QProblemB::setupAuxiliaryQPbounds( BooleanType useRelaxation )
01162 {
01163         int i;
01164         int nV = getNV( );
01165 
01166 
01167         /* Setup bound vectors. */
01168         for ( i=0; i<nV; ++i )
01169         {
01170                 switch ( bounds.getStatus( i ) )
01171                 {
01172                         case ST_INACTIVE:
01173                                 if ( useRelaxation == BT_TRUE )
01174                                 {
01175                                         if ( bounds.getType( i ) == ST_EQUALITY )
01176                                         {
01177                                                 lb[i] = x[i];
01178                                                 ub[i] = x[i];
01179                                         }
01180                                         else
01181                                         {
01182                                                 lb[i] = x[i] - BOUNDRELAXATION;
01183                                                 ub[i] = x[i] + BOUNDRELAXATION;
01184                                         }
01185                                 }
01186                                 break;
01187 
01188                         case ST_LOWER:
01189                                 lb[i] = x[i];
01190                                 if ( bounds.getType( i ) == ST_EQUALITY )
01191                                 {
01192                                         ub[i] = x[i];
01193                                 }
01194                                 else
01195                                 {
01196                                         if ( useRelaxation == BT_TRUE )
01197                                                 ub[i] = x[i] + BOUNDRELAXATION;
01198                                 }
01199                                 break;
01200 
01201                         case ST_UPPER:
01202                                 ub[i] = x[i];
01203                                 if ( bounds.getType( i ) == ST_EQUALITY )
01204                                 {
01205                                         lb[i] = x[i];
01206                                 }
01207                                 else
01208                                 {
01209                                         if ( useRelaxation == BT_TRUE )
01210                                                 lb[i] = x[i] - BOUNDRELAXATION;
01211                                 }
01212                                 break;
01213 
01214                         default:
01215                                 return THROWERROR( RET_UNKNOWN_BUG );
01216                 }
01217         }
01218 
01219         return SUCCESSFUL_RETURN;
01220 }
01221 
01222 
01223 /*
01224  *      a d d B o u n d
01225  */
01226 returnValue QProblemB::addBound(        int number, SubjectToStatus B_status,
01227                                                                         BooleanType updateCholesky
01228                                                                         )
01229 {
01230         int i, j;
01231         int nFR = getNFR( );
01232 
01233 
01234         /* consistency check */
01235         if ( ( getStatus( ) == QPS_NOTINITIALISED )    ||
01236                  ( getStatus( ) == QPS_AUXILIARYQPSOLVED ) ||
01237                  ( getStatus( ) == QPS_HOMOTOPYQPSOLVED )  ||
01238                  ( getStatus( ) == QPS_SOLVED )            )
01239         {
01240                 return THROWERROR( RET_UNKNOWN_BUG );
01241         }
01242 
01243         /* Perform cholesky updates only if QProblemB has been initialised! */
01244         if ( ( getStatus( ) == QPS_PREPARINGAUXILIARYQP ) || ( updateCholesky == BT_FALSE ) )
01245         {
01246                 /* UPDATE INDICES */
01247                 if ( bounds.moveFreeToFixed( number,B_status ) != SUCCESSFUL_RETURN )
01248                         return THROWERROR( RET_ADDBOUND_FAILED );
01249 
01250                 return SUCCESSFUL_RETURN;
01251         }
01252 
01253 
01254         /* I) PERFORM CHOLESKY UPDATE: */
01255         /* 1) Index of variable to be added within the list of free variables. */
01256         int number_idx = bounds.getFree( )->getIndex( number );
01257 
01258         real_t c, s;
01259 
01260         /* 2) Use row-wise Givens rotations to restore upper triangular form of R. */
01261         for( i=number_idx+1; i<nFR; ++i )
01262         {
01263                 computeGivens( R[(i-1)*NVMAX + i],R[i*NVMAX + i], R[(i-1)*NVMAX + i],R[i*NVMAX + i],c,s );
01264 
01265                 for( j=(1+i); j<nFR; ++j ) /* last column of R is thrown away */
01266                         applyGivens( c,s,R[(i-1)*NVMAX + j],R[i*NVMAX + j], R[(i-1)*NVMAX + j],R[i*NVMAX + j] );
01267         }
01268 
01269         /* 3) Delete <number_idx>th column and ... */
01270         for( i=0; i<nFR-1; ++i )
01271                 for( j=number_idx+1; j<nFR; ++j )
01272                         R[i*NVMAX + j-1] = R[i*NVMAX + j];
01273         /* ... last column of R. */
01274         for( i=0; i<nFR; ++i )
01275                 R[i*NVMAX + nFR-1] = 0.0;
01276 
01277 
01278         /* II) UPDATE INDICES */
01279         if ( bounds.moveFreeToFixed( number,B_status ) != SUCCESSFUL_RETURN )
01280                 return THROWERROR( RET_ADDBOUND_FAILED );
01281 
01282 
01283         return SUCCESSFUL_RETURN;
01284 }
01285 
01286 
01287 returnValue QProblemB::removeBound(     int number,
01288                                                                         BooleanType updateCholesky
01289                                                                         )
01290 {
01291         int i, ii;
01292         int nFR = getNFR( );
01293 
01294 
01295         /* consistency check */
01296         if ( ( getStatus( ) == QPS_NOTINITIALISED )    ||
01297                  ( getStatus( ) == QPS_AUXILIARYQPSOLVED ) ||
01298                  ( getStatus( ) == QPS_HOMOTOPYQPSOLVED )  ||
01299                  ( getStatus( ) == QPS_SOLVED )            )
01300         {
01301                 return THROWERROR( RET_UNKNOWN_BUG );
01302         }
01303 
01304 
01305         /* I) UPDATE INDICES */
01306         if ( bounds.moveFixedToFree( number ) != SUCCESSFUL_RETURN )
01307                 return THROWERROR( RET_REMOVEBOUND_FAILED );
01308 
01309         /* Perform cholesky updates only if QProblemB has been initialised! */
01310         if ( ( getStatus( ) == QPS_PREPARINGAUXILIARYQP ) || ( updateCholesky == BT_FALSE ) )
01311                 return SUCCESSFUL_RETURN;
01312 
01313 
01314         /* II) PERFORM CHOLESKY UPDATE */
01315         int FR_idx[NVMAX];
01316         if ( bounds.getFree( )->getNumberArray( FR_idx ) != SUCCESSFUL_RETURN )
01317                 return THROWERROR( RET_REMOVEBOUND_FAILED );
01318 
01319         /* 1) Calculate new column of cholesky decomposition. */
01320         real_t rhs[NVMAX];
01321         real_t r[NVMAX];
01322         real_t r0 = H[number*NVMAX + number];
01323 
01324         for( i=0; i<nFR; ++i )
01325         {
01326                 ii = FR_idx[i];
01327                 rhs[i] = H[number*NVMAX + ii];
01328         }
01329 
01330         if ( backsolveR( rhs,BT_TRUE,BT_TRUE,r ) != SUCCESSFUL_RETURN )
01331                 return THROWERROR( RET_REMOVEBOUND_FAILED );
01332 
01333         for( i=0; i<nFR; ++i )
01334                 r0 -= r[i]*r[i];
01335 
01336         /* 2) Store new column into R. */
01337         for( i=0; i<nFR; ++i )
01338                 R[i*NVMAX + nFR] = r[i];
01339 
01340         if ( r0 > 0.0 )
01341                 R[nFR*NVMAX + nFR] = sqrt( r0 );
01342         else
01343         {
01344                 hessianType = HST_SEMIDEF;
01345                 return THROWERROR( RET_HESSIAN_NOT_SPD );
01346         }
01347 
01348 
01349         return SUCCESSFUL_RETURN;
01350 }
01351 
01352 
01353 /*
01354  *      b a c k s o l v e R  (CODE DUPLICATED IN QProblem CLASS!!!)
01355  */
01356 returnValue QProblemB::backsolveR(      const real_t* const b, BooleanType transposed,
01357                                                                         real_t* const a
01358                                                                         )
01359 {
01360         /* Call standard backsolve procedure (i.e. removingBound == BT_FALSE). */
01361         return backsolveR( b,transposed,BT_FALSE,a );
01362 }
01363 
01364 
01365 /*
01366  *      b a c k s o l v e R  (CODE DUPLICATED IN QProblem CLASS!!!)
01367  */
01368 returnValue QProblemB::backsolveR(      const real_t* const b, BooleanType transposed,
01369                                                                         BooleanType removingBound,
01370                                                                         real_t* const a
01371                                                                         )
01372 {
01373         int i, j;
01374         int nR = getNZ( );
01375 
01376         real_t sum;
01377 
01378         /* if backsolve is called while removing a bound, reduce nZ by one. */
01379         if ( removingBound == BT_TRUE )
01380                 --nR;
01381 
01382         /* nothing to do */
01383         if ( nR <= 0 )
01384                 return SUCCESSFUL_RETURN;
01385 
01386 
01387         /* Solve Ra = b, where R might be transposed. */
01388         if ( transposed == BT_FALSE )
01389         {
01390                 /* solve Ra = b */
01391                 for( i=(nR-1); i>=0; --i )
01392                 {
01393                         sum = b[i];
01394                         for( j=(i+1); j<nR; ++j )
01395                                 sum -= R[i*NVMAX + j] * a[j];
01396 
01397                         if ( getAbs( R[i*NVMAX + i] ) > ZERO )
01398                                 a[i] = sum / R[i*NVMAX + i];
01399                         else
01400                                 return THROWERROR( RET_DIV_BY_ZERO );
01401                 }
01402         }
01403         else
01404         {
01405                 /* solve R^T*a = b */
01406                 for( i=0; i<nR; ++i )
01407                 {
01408                         sum = b[i];
01409 
01410                         for( j=0; j<i; ++j )
01411                                 sum -= R[j*NVMAX + i] * a[j];
01412 
01413                         if ( getAbs( R[i*NVMAX + i] ) > ZERO )
01414                                 a[i] = sum / R[i*NVMAX + i];
01415                         else
01416                                 return THROWERROR( RET_DIV_BY_ZERO );
01417                 }
01418         }
01419 
01420         return SUCCESSFUL_RETURN;
01421 }
01422 
01423 
01424 /*
01425  *      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
01426  */
01427 returnValue QProblemB::hotstart_determineDataShift(     const int* const FX_idx,
01428                                                                                                         const real_t* const g_new, const real_t* const lb_new, const real_t* const ub_new,
01429                                                                                                         real_t* const delta_g, real_t* const delta_lb, real_t* const delta_ub,
01430                                                                                                         BooleanType& Delta_bB_isZero
01431                                                                                                         )
01432 {
01433         int i, ii;
01434         int nV  = getNV( );
01435         int nFX = getNFX( );
01436 
01437 
01438         /* 1) Calculate shift directions. */
01439         for( i=0; i<nV; ++i )
01440                 delta_g[i]  = g_new[i]  - g[i];
01441 
01442         if ( lb_new != 0 )
01443         {
01444                 for( i=0; i<nV; ++i )
01445                         delta_lb[i] = lb_new[i] - lb[i];
01446         }
01447         else
01448         {
01449                 /* if no lower bounds exist, assume the new lower bounds to be -infinity */
01450                 for( i=0; i<nV; ++i )
01451                         delta_lb[i] = -INFTY - lb[i];
01452         }
01453 
01454         if ( ub_new != 0 )
01455         {
01456                 for( i=0; i<nV; ++i )
01457                         delta_ub[i] = ub_new[i] - ub[i];
01458         }
01459         else
01460         {
01461                 /* if no upper bounds exist, assume the new upper bounds to be infinity */
01462                 for( i=0; i<nV; ++i )
01463                         delta_ub[i] = INFTY - ub[i];
01464         }
01465 
01466         /* 2) Determine if active bounds are to be shifted. */
01467         Delta_bB_isZero = BT_TRUE;
01468 
01469         for ( i=0; i<nFX; ++i )
01470         {
01471                 ii = FX_idx[i];
01472 
01473                 if ( ( getAbs( delta_lb[ii] ) > EPS ) || ( getAbs( delta_ub[ii] ) > EPS ) )
01474                 {
01475                         Delta_bB_isZero = BT_FALSE;
01476                         break;
01477                 }
01478         }
01479 
01480         return SUCCESSFUL_RETURN;
01481 }
01482 
01483 
01484 /*
01485  *      a r e B o u n d s C o n s i s t e n t
01486  */
01487 BooleanType QProblemB::areBoundsConsistent(     const real_t* const delta_lb, const real_t* const delta_ub
01488                                                                                         ) const
01489 {
01490         int i;
01491 
01492         /* Check if delta_lb[i] is greater than delta_ub[i]
01493          * for a component i whose bounds are already (numerically) equal. */
01494         for( i=0; i<getNV( ); ++i )
01495                 if ( ( lb[i] > ub[i] - BOUNDTOL ) && ( delta_lb[i] > delta_ub[i] + EPS ) )
01496                         return BT_FALSE;
01497 
01498         return BT_TRUE;
01499 }
01500 
01501 
01502 /*
01503  *      s e t u p Q P d a t a
01504  */
01505 returnValue QProblemB::setupQPdata(     const real_t* const _H, const real_t* const _g,
01506                                                                         const real_t* const _lb, const real_t* const _ub
01507                                                                         )
01508 {
01509         int i, j;
01510         int nV = getNV( );
01511 
01512         /* 1) Setup Hessian matrix. */
01513         if ( _H == 0 )
01514                 return THROWERROR( RET_INVALID_ARGUMENTS );
01515 
01516         for( i=0; i<nV; ++i )
01517                 for( j=0; j<nV; ++j )
01518                         H[i*NVMAX + j] = _H[i*nV + j];
01519 
01520         /* 2) Setup gradient vector. */
01521         if ( _g == 0 )
01522                 return THROWERROR( RET_INVALID_ARGUMENTS );
01523 
01524         for( i=0; i<nV; ++i )
01525                 g[i] = _g[i];
01526 
01527         /* 3) Setup lower bounds vector. */
01528         if ( _lb != 0 )
01529         {
01530                 for( i=0; i<nV; ++i )
01531                         lb[i] = _lb[i];
01532         }
01533         else
01534         {
01535                 /* if no lower bounds are specified, set them to -infinity */
01536                 for( i=0; i<nV; ++i )
01537                         lb[i] = -INFTY;
01538         }
01539 
01540         /* 4) Setup upper bounds vector. */
01541         if ( _ub != 0 )
01542         {
01543                 for( i=0; i<nV; ++i )
01544                         ub[i] = _ub[i];
01545         }
01546         else
01547         {
01548                 /* if no upper bounds are specified, set them to infinity */
01549                 for( i=0; i<nV; ++i )
01550                         ub[i] = INFTY;
01551         }
01552 
01553         //printmatrix( "H",H,nV,nV );
01554         //printmatrix( "g",g,1,nV );
01555         //printmatrix( "lb",lb,1,nV );
01556         //printmatrix( "ub",ub,1,nV );
01557 
01558         return SUCCESSFUL_RETURN;
01559 }
01560 
01561 
01562 
01563 /*****************************************************************************
01564  *  P R I V A T E                                                            *
01565  *****************************************************************************/
01566 
01567 /*
01568  *      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
01569  */
01570 returnValue QProblemB::hotstart_determineStepDirection( const int* const FR_idx, const int* const FX_idx,
01571                                                                                                                 const real_t* const delta_g, const real_t* const delta_lb, const real_t* const delta_ub,
01572                                                                                                                 BooleanType Delta_bB_isZero,
01573                                                                                                                 real_t* const delta_xFX, real_t* const delta_xFR,
01574                                                                                                                 real_t* const delta_yFX
01575                                                                                                                 )
01576 {
01577         int i, j, ii, jj;
01578         int nFR = getNFR( );
01579         int nFX = getNFX( );
01580 
01581 
01582         /* initialise auxiliary vectors */
01583         real_t HMX_delta_xFX[NVMAX];
01584         for( i=0; i<nFR; ++i )
01585                 HMX_delta_xFX[i] = 0.0;
01586 
01587 
01588         /* I) DETERMINE delta_xFX */
01589         if ( nFX > 0 )
01590         {
01591                 for( i=0; i<nFX; ++i )
01592                 {
01593                         ii = FX_idx[i];
01594 
01595                         if ( bounds.getStatus( ii ) == ST_LOWER )
01596                                 delta_xFX[i] = delta_lb[ii];
01597                         else
01598                                 delta_xFX[i] = delta_ub[ii];
01599                 }
01600         }
01601 
01602 
01603         /* II) DETERMINE delta_xFR */
01604         if ( nFR > 0 )
01605         {
01606                 /* auxiliary variables */
01607                 real_t delta_xFRz_TMP[NVMAX];
01608                 real_t delta_xFRz_RHS[NVMAX];
01609 
01610                 /* Determine delta_xFRz. */
01611                 if ( Delta_bB_isZero == BT_FALSE )
01612                 {
01613                         for( i=0; i<nFR; ++i )
01614                         {
01615                                 ii = FR_idx[i];
01616                                 for( j=0; j<nFX; ++j )
01617                                 {
01618                                         jj = FX_idx[j];
01619                                         HMX_delta_xFX[i] += H[ii*NVMAX + jj] * delta_xFX[j];
01620                                 }
01621                         }
01622                 }
01623 
01624                 if ( Delta_bB_isZero == BT_TRUE )
01625                 {
01626                         for( j=0; j<nFR; ++j )
01627                         {
01628                                 jj = FR_idx[j];
01629                                 delta_xFRz_RHS[j] = delta_g[jj];
01630                         }
01631                 }
01632                 else
01633                 {
01634                         for( j=0; j<nFR; ++j )
01635                         {
01636                                 jj = FR_idx[j];
01637                                 delta_xFRz_RHS[j] = delta_g[jj] + HMX_delta_xFX[j]; /* *ZFR */
01638                         }
01639                 }
01640 
01641                 for( i=0; i<nFR; ++i )
01642                         delta_xFR[i] = -delta_xFRz_RHS[i];
01643 
01644                 if ( backsolveR( delta_xFR,BT_TRUE,delta_xFRz_TMP ) != SUCCESSFUL_RETURN )
01645                         return THROWERROR( RET_STEPDIRECTION_FAILED_CHOLESKY );
01646 
01647                 if ( backsolveR( delta_xFRz_TMP,BT_FALSE,delta_xFR ) != SUCCESSFUL_RETURN )
01648                         return THROWERROR( RET_STEPDIRECTION_FAILED_CHOLESKY );
01649         }
01650 
01651 
01652         /* III) DETERMINE delta_yFX */
01653         if ( nFX > 0 )
01654         {
01655                 for( i=0; i<nFX; ++i )
01656                 {
01657                         ii = FX_idx[i];
01658 
01659                         delta_yFX[i] = 0.0;
01660                         for( j=0; j<nFR; ++j )
01661                         {
01662                                 jj = FR_idx[j];
01663                                 delta_yFX[i] += H[ii*NVMAX + jj] * delta_xFR[j];
01664                         }
01665 
01666                         if ( Delta_bB_isZero == BT_FALSE )
01667                         {
01668                                 for( j=0; j<nFX; ++j )
01669                                 {
01670                                         jj = FX_idx[j];
01671                                         delta_yFX[i] += H[ii*NVMAX + jj] * delta_xFX[j];
01672                                 }
01673                         }
01674 
01675                         delta_yFX[i] += delta_g[ii];
01676                 }
01677         }
01678 
01679         return SUCCESSFUL_RETURN;
01680 }
01681 
01682 
01683 /*
01684  *      h o t s t a r t _ d e t e r m i n e S t e p L e n g t h
01685  */
01686 returnValue QProblemB::hotstart_determineStepLength(    const int* const FR_idx, const int* const FX_idx,
01687                                                                                                                 const real_t* const delta_lb, const real_t* const delta_ub,
01688                                                                                                                 const real_t* const delta_xFR,
01689                                                                                                                 const real_t* const delta_yFX,
01690                                                                                                                 int& BC_idx, SubjectToStatus& BC_status
01691                                                                                                                 )
01692 {
01693         int i, ii;
01694         int nFR = getNFR( );
01695         int nFX = getNFX( );
01696 
01697         real_t tau_tmp;
01698         real_t tau_new = 1.0;
01699 
01700         BC_idx = 0;
01701         BC_status = ST_UNDEFINED;
01702 
01703 
01704         /* I) DETERMINE MAXIMUM DUAL STEPLENGTH, i.e. ensure that
01705          *    active dual bounds remain valid (ignoring implicitly fixed variables): */
01706         for( i=0; i<nFX; ++i )
01707         {
01708                 ii = FX_idx[i];
01709 
01710                 if ( bounds.getType( ii ) != ST_EQUALITY )
01711                 {
01712                         if ( bounds.getStatus( ii ) == ST_LOWER )
01713                         {
01714                                 /* 1) Active lower bounds. */
01715                                 if ( ( delta_yFX[i] < -ZERO ) && ( y[ii] >= 0.0 ) )
01716                                 {
01717                                         tau_tmp = y[ii] / ( -delta_yFX[i] );
01718                                         if ( tau_tmp < tau_new )
01719                                         {
01720                                                 if ( tau_tmp >= 0.0 )
01721                                                 {
01722                                                         tau_new = tau_tmp;
01723                                                         BC_idx = ii;
01724                                                         BC_status = ST_INACTIVE;
01725                                                 }
01726                                         }
01727                                 }
01728                         }
01729                         else
01730                         {
01731                                 /* 2) Active upper bounds. */
01732                                 if ( ( delta_yFX[i] > ZERO ) && ( y[ii] <= 0.0 ) )
01733                                 {
01734                                         tau_tmp = y[ii] / ( -delta_yFX[i] );
01735                                         if ( tau_tmp < tau_new )
01736                                         {
01737                                                 if ( tau_tmp >= 0.0 )
01738                                                 {
01739                                                         tau_new = tau_tmp;
01740                                                         BC_idx = ii;
01741                                                         BC_status = ST_INACTIVE;
01742                                                 }
01743                                         }
01744                                 }
01745                         }
01746                 }
01747         }
01748 
01749 
01750         /* II) DETERMINE MAXIMUM PRIMAL STEPLENGTH, i.e. ensure that
01751          *     inactive bounds remain valid (ignoring unbounded variables). */
01752         /* 1) Inactive lower bounds. */
01753         if ( bounds.isNoLower( ) == BT_FALSE )
01754         {
01755                 for( i=0; i<nFR; ++i )
01756                 {
01757                         ii = FR_idx[i];
01758 
01759                         if ( bounds.getType( ii ) != ST_UNBOUNDED )
01760                         {
01761                                 if ( delta_lb[ii] > delta_xFR[i] )
01762                                 {
01763                                         if ( x[ii] > lb[ii] )
01764                                                 tau_tmp = ( x[ii] - lb[ii] ) / ( delta_lb[ii] - delta_xFR[i] );
01765                                         else
01766                                                 tau_tmp = 0.0;
01767 
01768                                         if ( tau_tmp < tau_new )
01769                                         {
01770                                                 if ( tau_tmp >= 0.0 )
01771                                                 {
01772                                                         tau_new = tau_tmp;
01773                                                         BC_idx = ii;
01774                                                         BC_status = ST_LOWER;
01775                                                 }
01776                                         }
01777                                 }
01778                         }
01779                 }
01780         }
01781 
01782         /* 2) Inactive upper bounds. */
01783         if ( bounds.isNoUpper( ) == BT_FALSE )
01784         {
01785                 for( i=0; i<nFR; ++i )
01786                 {
01787                         ii = FR_idx[i];
01788 
01789                         if ( bounds.getType( ii ) != ST_UNBOUNDED )
01790                         {
01791                                 if ( delta_ub[ii] < delta_xFR[i] )
01792                                 {
01793                                         if ( x[ii] < ub[ii] )
01794                                                 tau_tmp = ( x[ii] - ub[ii] ) / ( delta_ub[ii] - delta_xFR[i] );
01795                                         else
01796                                                 tau_tmp = 0.0;
01797 
01798                                         if ( tau_tmp < tau_new )
01799                                         {
01800                                                 if ( tau_tmp >= 0.0 )
01801                                                 {
01802                                                         tau_new = tau_tmp;
01803                                                         BC_idx = ii;
01804                                                         BC_status = ST_UPPER;
01805                                                 }
01806                                         }
01807                                 }
01808                         }
01809                 }
01810         }
01811 
01812 
01813         /* III) SET MAXIMUM HOMOTOPY STEPLENGTH */
01814         tau = tau_new;
01815 
01816         if ( printlevel ==  PL_HIGH )
01817         {
01818                 #ifdef PC_DEBUG
01819                 char messageString[80];
01820 
01821                 if ( BC_status == ST_UNDEFINED )
01822                         sprintf( messageString,"Stepsize is %.6e!",tau );
01823                 else
01824                         sprintf( messageString,"Stepsize is %.6e! (BC_idx = %d, BC_status = %d)",tau,BC_idx,BC_status );
01825 
01826                 getGlobalMessageHandler( )->throwInfo( RET_STEPSIZE_NONPOSITIVE,messageString,__FUNCTION__,__FILE__,__LINE__,VS_VISIBLE );
01827                 #endif
01828         }
01829 
01830         return SUCCESSFUL_RETURN;
01831 }
01832 
01833 
01834 /*
01835  *      h o t s t a r t _ p e r f o r m S t e p
01836  */
01837 returnValue QProblemB::hotstart_performStep(    const int* const FR_idx, const int* const FX_idx,
01838                                                                                                 const real_t* const delta_g, const real_t* const  delta_lb, const real_t* const delta_ub,
01839                                                                                                 const real_t* const delta_xFX, const real_t* const delta_xFR,
01840                                                                                                 const real_t* const delta_yFX,
01841                                                                                                 int BC_idx, SubjectToStatus BC_status
01842                                                                                                 )
01843 {
01844         int i, ii;
01845         int nV  = getNV( );
01846         int nFR = getNFR( );
01847         int nFX = getNFX( );
01848 
01849 
01850         /* I) CHECK BOUNDS' CONSISTENCY */
01851         if ( areBoundsConsistent( delta_lb,delta_ub ) == BT_FALSE )
01852         {
01853                 infeasible = BT_TRUE;
01854                 tau = 0.0;
01855 
01856                 return THROWERROR( RET_QP_INFEASIBLE );
01857         }
01858 
01859 
01860         /* II) GO TO ACTIVE SET CHANGE */
01861         if ( tau > ZERO )
01862         {
01863                 /* 1) Perform step in primal und dual space. */
01864                 for( i=0; i<nFR; ++i )
01865                 {
01866                         ii = FR_idx[i];
01867                         x[ii] += tau*delta_xFR[i];
01868                 }
01869 
01870                 for( i=0; i<nFX; ++i )
01871                 {
01872                         ii = FX_idx[i];
01873                         x[ii] += tau*delta_xFX[i];
01874                         y[ii] += tau*delta_yFX[i];
01875                 }
01876 
01877                 /* 2) Shift QP data. */
01878                 for( i=0; i<nV; ++i )
01879                 {
01880                         g[i]  += tau*delta_g[i];
01881                         lb[i] += tau*delta_lb[i];
01882                         ub[i] += tau*delta_ub[i];
01883                 }
01884         }
01885         else
01886         {
01887                 /* print a stepsize warning if stepsize is zero */
01888                 #ifdef PC_DEBUG
01889                 char messageString[80];
01890                 sprintf( messageString,"Stepsize is %.6e",tau );
01891                 getGlobalMessageHandler( )->throwWarning( RET_STEPSIZE,messageString,__FUNCTION__,__FILE__,__LINE__,VS_VISIBLE );
01892                 #endif
01893         }
01894 
01895 
01896         /* setup output preferences */
01897         #ifdef PC_DEBUG
01898         char messageString[80];
01899         VisibilityStatus visibilityStatus;
01900 
01901         if ( printlevel == PL_HIGH )
01902                 visibilityStatus = VS_VISIBLE;
01903         else
01904                 visibilityStatus = VS_HIDDEN;
01905         #endif
01906 
01907 
01908         /* III) UPDATE ACTIVE SET */
01909         switch ( BC_status )
01910         {
01911                 /* Optimal solution found as no working set change detected. */
01912                 case ST_UNDEFINED:
01913                         return RET_OPTIMAL_SOLUTION_FOUND;
01914 
01915 
01916                 /* Remove one variable from active set. */
01917                 case ST_INACTIVE:
01918                         #ifdef PC_DEBUG
01919                         sprintf( messageString,"bound no. %d.", BC_idx );
01920                         getGlobalMessageHandler( )->throwInfo( RET_REMOVE_FROM_ACTIVESET,messageString,__FUNCTION__,__FILE__,__LINE__,visibilityStatus );
01921                         #endif
01922 
01923                         if ( removeBound( BC_idx,BT_TRUE ) != SUCCESSFUL_RETURN )
01924                                 return THROWERROR( RET_REMOVE_FROM_ACTIVESET_FAILED );
01925 
01926                         y[BC_idx] = 0.0;
01927                         break;
01928 
01929 
01930                 /* Add one variable to active set. */
01931                 default:
01932                         #ifdef PC_DEBUG
01933                         if ( BC_status == ST_LOWER )
01934                                 sprintf( messageString,"lower bound no. %d.", BC_idx );
01935                         else
01936                                 sprintf( messageString,"upper bound no. %d.", BC_idx );
01937                                 getGlobalMessageHandler( )->throwInfo( RET_ADD_TO_ACTIVESET,messageString,__FUNCTION__,__FILE__,__LINE__,visibilityStatus );
01938                         #endif
01939 
01940                         if ( addBound( BC_idx,BC_status,BT_TRUE ) != SUCCESSFUL_RETURN )
01941                                 return THROWERROR( RET_ADD_TO_ACTIVESET_FAILED );
01942                         break;
01943         }
01944 
01945         return SUCCESSFUL_RETURN;
01946 }
01947 
01948 
01949 #ifdef PC_DEBUG  /* Define print functions only for debugging! */
01950 
01951 /*
01952  *      p r i n t I t e r a t i o n
01953  */
01954 returnValue QProblemB::printIteration(  int iteration,
01955                                                                                 int BC_idx,     SubjectToStatus BC_status
01956                                                                                 )
01957 {
01958         char myPrintfString[160];
01959 
01960         /* consistency check */
01961         if ( iteration < 0 )
01962                 return THROWERROR( RET_INVALID_ARGUMENTS );
01963 
01964         /* nothing to do */
01965         if ( printlevel != PL_MEDIUM )
01966                 return SUCCESSFUL_RETURN;
01967 
01968 
01969         /* 1) Print header at first iteration. */
01970         if ( iteration == 0 )
01971         {
01972                 sprintf( myPrintfString,"\n##############  qpOASES  --  QP NO.%4.1d  ###############\n", count );
01973                 myPrintf( myPrintfString );
01974 
01975                 sprintf( myPrintfString,"   Iter   |   StepLength    |       Info      |   nFX   \n" );
01976                 myPrintf( myPrintfString );
01977         }
01978 
01979         /* 2) Print iteration line. */
01980         if ( BC_status == ST_UNDEFINED )
01981         {
01982                 sprintf( myPrintfString,"   %4.1d   |   %1.5e   |    QP SOLVED    |  %4.1d   \n", iteration,tau,getNFX( ) );
01983                 myPrintf( myPrintfString );
01984         }
01985         else
01986         {
01987                 char info[8];
01988 
01989                 if ( BC_status == ST_INACTIVE )
01990                         sprintf( info,"REM BND" );
01991                 else
01992                         sprintf( info,"ADD BND" );
01993 
01994                 sprintf( myPrintfString,"   %4.1d   |   %1.5e   |   %s%4.1d   |  %4.1d   \n", iteration,tau,info,BC_idx,getNFX( ) );
01995                 myPrintf( myPrintfString );
01996         }
01997 
01998         return SUCCESSFUL_RETURN;
01999 }
02000 
02001 #endif  /* PC_DEBUG */
02002 
02003 
02004 
02005 /*
02006  *      c h e c k K K T c o n d i t i o n s
02007  */
02008 returnValue QProblemB::checkKKTconditions( )
02009 {
02010         #ifdef __PERFORM_KKT_TEST__
02011 
02012         int i, j;
02013         int nV = getNV( );
02014 
02015         real_t tmp;
02016         real_t maxKKTviolation = 0.0;
02017 
02018 
02019         /* 1) Check for Hx + g - y*A' = 0  (here: A = Id). */
02020         for( i=0; i<nV; ++i )
02021         {
02022                 tmp = g[i];
02023 
02024                 for( j=0; j<nV; ++j )
02025                         tmp += H[i*nV + j] * x[j];
02026 
02027                 tmp -= y[i];
02028 
02029                 if ( getAbs( tmp ) > maxKKTviolation )
02030                         maxKKTviolation = getAbs( tmp );
02031         }
02032 
02033         /* 2) Check for lb <= x <= ub. */
02034         for( i=0; i<nV; ++i )
02035         {
02036                 if ( lb[i] - x[i] > maxKKTviolation )
02037                         maxKKTviolation = lb[i] - x[i];
02038 
02039                 if ( x[i] - ub[i] > maxKKTviolation )
02040                         maxKKTviolation = x[i] - ub[i];
02041         }
02042 
02043         /* 3) Check for correct sign of y and for complementary slackness. */
02044         for( i=0; i<nV; ++i )
02045         {
02046                 switch ( bounds.getStatus( i ) )
02047                 {
02048                         case ST_LOWER:
02049                                 if ( -y[i] > maxKKTviolation )
02050                                         maxKKTviolation = -y[i];
02051                                 if ( getAbs( ( x[i] - lb[i] ) * y[i] ) > maxKKTviolation )
02052                                         maxKKTviolation = getAbs( ( x[i] - lb[i] ) * y[i] );
02053                                 break;
02054 
02055                         case ST_UPPER:
02056                                 if ( y[i] > maxKKTviolation )
02057                                         maxKKTviolation = y[i];
02058                                 if ( getAbs( ( ub[i] - x[i] ) * y[i] ) > maxKKTviolation )
02059                                         maxKKTviolation = getAbs( ( ub[i] - x[i] ) * y[i] );
02060                                 break;
02061 
02062                         default: /* inactive */
02063                         if ( getAbs( y[i] ) > maxKKTviolation )
02064                                         maxKKTviolation = getAbs( y[i] );
02065                                 break;
02066                 }
02067         }
02068 
02069         if ( maxKKTviolation > CRITICALACCURACY )
02070                 return RET_NO_SOLUTION;
02071 
02072         if ( maxKKTviolation > DESIREDACCURACY )
02073                 return RET_INACCURATE_SOLUTION;
02074 
02075         #endif /* __PERFORM_KKT_TEST__ */
02076 
02077         return SUCCESSFUL_RETURN;
02078 }
02079 
02080 
02081 
02082 /*
02083  *      end of file
02084  */


acado
Author(s): Milan Vukov, Rien Quirynen
autogenerated on Thu Aug 27 2015 11:59:50