You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3868 lines
94 KiB
3868 lines
94 KiB
8 years ago
|
/*
|
||
|
* 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 <QProblem.hpp>
|
||
|
|
||
|
#include <stdio.h>
|
||
|
|
||
|
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; i<sizeT; ++i )
|
||
|
for( j=0; j<sizeT; ++j )
|
||
|
T[i*NVMAX + j] = rhs.T[i*NVMAX + j];
|
||
|
|
||
|
for( i=0; i<_nV; ++i )
|
||
|
for( j=0; j<_nV; ++j )
|
||
|
Q[i*NVMAX + j] = rhs.Q[i*NVMAX + j];
|
||
|
|
||
|
for( i=0; i<_nC; ++i )
|
||
|
Ax[i] = rhs.Ax[i];
|
||
|
|
||
|
cyclingManager = rhs.cyclingManager;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* ~ Q P r o b l e m
|
||
|
*/
|
||
|
QProblem::~QProblem( )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* o p e r a t o r =
|
||
|
*/
|
||
|
QProblem& QProblem::operator=( const QProblem& rhs )
|
||
|
{
|
||
|
int i, j;
|
||
|
|
||
|
if ( this != &rhs )
|
||
|
{
|
||
|
QProblemB::operator=( rhs );
|
||
|
|
||
|
|
||
|
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; i<sizeT; ++i )
|
||
|
for( j=0; j<sizeT; ++j )
|
||
|
T[i*NVMAX + j] = rhs.T[i*NVMAX + j];
|
||
|
|
||
|
for( i=0; i<_nV; ++i )
|
||
|
for( j=0; j<_nV; ++j )
|
||
|
Q[i*NVMAX + j] = rhs.Q[i*NVMAX + j];
|
||
|
|
||
|
for( i=0; i<_nC; ++i )
|
||
|
Ax[i] = rhs.Ax[i];
|
||
|
|
||
|
cyclingManager = rhs.cyclingManager;
|
||
|
}
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* r e s e t
|
||
|
*/
|
||
|
returnValue QProblem::reset( )
|
||
|
{
|
||
|
int i, j;
|
||
|
int nV = getNV( );
|
||
|
int nC = getNC( );
|
||
|
|
||
|
|
||
|
/* 1) Reset bounds, Cholesky decomposition and status flags. */
|
||
|
if ( QProblemB::reset( ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_RESET_FAILED );
|
||
|
|
||
|
/* 2) Reset constraints. */
|
||
|
constraints.init( nC );
|
||
|
|
||
|
/* 3) Reset TQ factorisation. */
|
||
|
for( i=0; i<sizeT; ++i )
|
||
|
for( j=0; j<sizeT; ++j )
|
||
|
T[i*NVMAX + j] = 0.0;
|
||
|
|
||
|
for( i=0; i<nV; ++i )
|
||
|
for( j=0; j<nV; ++j )
|
||
|
Q[i*NVMAX + j] = 0.0;
|
||
|
|
||
|
/* 4) Reset cycling manager. */
|
||
|
if ( cyclingManager.clearCyclingData( ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_RESET_FAILED );
|
||
|
|
||
|
return SUCCESSFUL_RETURN;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* i n i t
|
||
|
*/
|
||
|
returnValue QProblem::init( const real_t* const _H, 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& nWSR, const real_t* const yOpt, real_t* const cputime
|
||
|
)
|
||
|
{
|
||
|
/* 1) Setup QP data. */
|
||
|
if (setupQPdata(_H, 0, _g, _A, _lb, _ub, _lbA, _ubA) != SUCCESSFUL_RETURN)
|
||
|
return THROWERROR( RET_INVALID_ARGUMENTS );
|
||
|
|
||
|
/* 2) Call to main initialisation routine (without any additional information). */
|
||
|
return solveInitialQP( 0,yOpt,0,0, nWSR,cputime );
|
||
|
}
|
||
|
|
||
|
returnValue QProblem::init( 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& nWSR, const real_t* const yOpt, real_t* const cputime
|
||
|
)
|
||
|
{
|
||
|
/* 1) Setup QP data. */
|
||
|
if (setupQPdata(_H, _R, _g, _A, _lb, _ub, _lbA, _ubA) != SUCCESSFUL_RETURN)
|
||
|
return THROWERROR( RET_INVALID_ARGUMENTS );
|
||
|
|
||
|
/* 2) Call to main initialisation routine (without any additional information). */
|
||
|
return solveInitialQP( 0,yOpt,0,0, nWSR,cputime );
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* h o t s t a r t
|
||
|
*/
|
||
|
returnValue QProblem::hotstart( const real_t* const g_new, const real_t* const lb_new, const real_t* const ub_new,
|
||
|
const real_t* const lbA_new, const real_t* const ubA_new,
|
||
|
int& nWSR, real_t* const cputime
|
||
|
)
|
||
|
{
|
||
|
int l;
|
||
|
|
||
|
/* consistency check */
|
||
|
if ( ( getStatus( ) == QPS_NOTINITIALISED ) ||
|
||
|
( getStatus( ) == QPS_PREPARINGAUXILIARYQP ) ||
|
||
|
( getStatus( ) == QPS_PERFORMINGHOMOTOPY ) )
|
||
|
{
|
||
|
return THROWERROR( RET_HOTSTART_FAILED_AS_QP_NOT_INITIALISED );
|
||
|
}
|
||
|
|
||
|
/* start runtime measurement */
|
||
|
real_t starttime = 0.0;
|
||
|
if ( cputime != 0 )
|
||
|
starttime = getCPUtime( );
|
||
|
|
||
|
|
||
|
/* I) PREPARATIONS */
|
||
|
/* 1) Reset cycling and status flags and increase QP counter. */
|
||
|
cyclingManager.clearCyclingData( );
|
||
|
|
||
|
infeasible = BT_FALSE;
|
||
|
unbounded = BT_FALSE;
|
||
|
|
||
|
++count;
|
||
|
|
||
|
/* 2) Allocate delta vectors of gradient and (constraints') bounds. */
|
||
|
returnValue returnvalue;
|
||
|
BooleanType Delta_bC_isZero, Delta_bB_isZero;
|
||
|
|
||
|
int FR_idx[NVMAX];
|
||
|
int FX_idx[NVMAX];
|
||
|
int AC_idx[NCMAX_ALLOC];
|
||
|
int IAC_idx[NCMAX_ALLOC];
|
||
|
|
||
|
real_t delta_g[NVMAX];
|
||
|
real_t delta_lb[NVMAX];
|
||
|
real_t delta_ub[NVMAX];
|
||
|
real_t delta_lbA[NCMAX_ALLOC];
|
||
|
real_t delta_ubA[NCMAX_ALLOC];
|
||
|
|
||
|
real_t delta_xFR[NVMAX];
|
||
|
real_t delta_xFX[NVMAX];
|
||
|
real_t delta_yAC[NCMAX_ALLOC];
|
||
|
real_t delta_yFX[NVMAX];
|
||
|
real_t delta_Ax[NCMAX_ALLOC];
|
||
|
|
||
|
int BC_idx;
|
||
|
SubjectToStatus BC_status;
|
||
|
BooleanType BC_isBound;
|
||
|
|
||
|
#ifdef PC_DEBUG
|
||
|
char messageString[80];
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* II) MAIN HOMOTOPY LOOP */
|
||
|
for( l=0; l<nWSR; ++l )
|
||
|
{
|
||
|
status = QPS_PERFORMINGHOMOTOPY;
|
||
|
|
||
|
if ( printlevel == PL_HIGH )
|
||
|
{
|
||
|
#ifdef PC_DEBUG
|
||
|
sprintf( messageString,"%d ...",l );
|
||
|
getGlobalMessageHandler( )->throwInfo( 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<getNV( )+getNC( ); ++i )
|
||
|
yOpt[i] = y[i];
|
||
|
|
||
|
return SUCCESSFUL_RETURN;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return RET_QP_NOT_SOLVED;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
* P R O T E C T E D *
|
||
|
*****************************************************************************/
|
||
|
|
||
|
/*
|
||
|
* s e t u p S u b j e c t T o T y p e
|
||
|
*/
|
||
|
returnValue QProblem::setupSubjectToType( )
|
||
|
{
|
||
|
int i;
|
||
|
int nC = getNC( );
|
||
|
|
||
|
|
||
|
/* I) SETUP SUBJECTTOTYPE FOR BOUNDS */
|
||
|
if ( QProblemB::setupSubjectToType( ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_SETUPSUBJECTTOTYPE_FAILED );
|
||
|
|
||
|
|
||
|
/* II) SETUP SUBJECTTOTYPE FOR CONSTRAINTS */
|
||
|
/* 1) Check if lower constraints' bounds are present. */
|
||
|
constraints.setNoLower( BT_TRUE );
|
||
|
for( i=0; i<nC; ++i )
|
||
|
{
|
||
|
if ( lbA[i] > -INFTY )
|
||
|
{
|
||
|
constraints.setNoLower( BT_FALSE );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* 2) Check if upper constraints' bounds are present. */
|
||
|
constraints.setNoUpper( BT_TRUE );
|
||
|
for( i=0; i<nC; ++i )
|
||
|
{
|
||
|
if ( ubA[i] < INFTY )
|
||
|
{
|
||
|
constraints.setNoUpper( BT_FALSE );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* 3) Determine implicit equality constraints and unbounded constraints. */
|
||
|
int nEC = 0;
|
||
|
int nUC = 0;
|
||
|
|
||
|
for( i=0; i<nC; ++i )
|
||
|
{
|
||
|
if ( ( lbA[i] < -INFTY + BOUNDTOL ) && ( ubA[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<nV; ++i )
|
||
|
for( j=0; j<nV; ++j )
|
||
|
R[i*NVMAX + j] = 0.0;
|
||
|
|
||
|
/* 2) Calculate Cholesky decomposition of projected Hessian Z'*H*Z. */
|
||
|
if ( hessianType == HST_IDENTITY )
|
||
|
{
|
||
|
/* if Hessian is identity, so is its Cholesky factor. */
|
||
|
for( i=0; i<nV; ++i )
|
||
|
R[i*NVMAX + i] = 1.0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( nZ > 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<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
|
||
|
for ( j=0; j<nZ; ++j )
|
||
|
{
|
||
|
real_t sum = 0.0;
|
||
|
for ( k=0; k<nFR; ++k )
|
||
|
{
|
||
|
kk = FR_idx[k];
|
||
|
sum += H[ii*NVMAX + kk] * Q[kk*NVMAX + j];
|
||
|
}
|
||
|
HZ[i * NVMAX + j] = sum;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* calculate Z'*H*Z */
|
||
|
for ( i=0; i<nZ; ++i )
|
||
|
for ( j=0; j<nZ; ++j )
|
||
|
{
|
||
|
real_t sum = 0.0;
|
||
|
for ( k=0; k<nFR; ++k )
|
||
|
{
|
||
|
kk = FR_idx[k];
|
||
|
sum += Q[kk*NVMAX + i] * HZ[k*NVMAX + j];
|
||
|
}
|
||
|
ZHZ[i * NVMAX + j] = sum;
|
||
|
}
|
||
|
|
||
|
/* R'*R = Z'*H*Z */
|
||
|
real_t sum, inv;
|
||
|
|
||
|
for( i=0; i<nZ; ++i )
|
||
|
{
|
||
|
/* j == i */
|
||
|
sum = ZHZ[i*NVMAX + i];
|
||
|
|
||
|
for( k=(i-1); k>=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<nZ; ++j )
|
||
|
{
|
||
|
sum = ZHZ[j*NVMAX + i];
|
||
|
|
||
|
for( k=(i-1); k>=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; i<nV; ++i )
|
||
|
for( j=0; j<nV; ++j )
|
||
|
Q[i*NVMAX + j] = 0.0;
|
||
|
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
Q[ii*NVMAX + i] = 1.0;
|
||
|
}
|
||
|
|
||
|
/* 2) Set T to zero matrix. */
|
||
|
for( i=0; i<sizeT; ++i )
|
||
|
for( j=0; j<sizeT; ++j )
|
||
|
T[i*NVMAX + j] = 0.0;
|
||
|
|
||
|
return SUCCESSFUL_RETURN;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* s o l v e I n i t i a l Q P
|
||
|
*/
|
||
|
returnValue QProblem::solveInitialQP( const real_t* const xOpt, const real_t* const yOpt,
|
||
|
const Bounds* const guessedBounds, const Constraints* const guessedConstraints,
|
||
|
int& nWSR, real_t* const cputime
|
||
|
)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
/* some definitions */
|
||
|
int nV = getNV( );
|
||
|
int nC = getNC( );
|
||
|
|
||
|
|
||
|
/* start runtime measurement */
|
||
|
real_t starttime = 0.0;
|
||
|
if ( cputime != 0 )
|
||
|
starttime = getCPUtime( );
|
||
|
|
||
|
|
||
|
status = QPS_NOTINITIALISED;
|
||
|
|
||
|
/* I) ANALYSE QP DATA: */
|
||
|
/* 1) Check if Hessian happens to be the identity matrix. */
|
||
|
if ( checkForIdentityHessian( ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_INIT_FAILED );
|
||
|
|
||
|
/* 2) Setup type of bounds and constraints (i.e. unbounded, implicitly fixed etc.). */
|
||
|
if ( setupSubjectToType( ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_INIT_FAILED );
|
||
|
|
||
|
/* 3) Initialise cycling manager. */
|
||
|
cyclingManager.clearCyclingData( );
|
||
|
|
||
|
status = QPS_PREPARINGAUXILIARYQP;
|
||
|
|
||
|
|
||
|
/* II) SETUP AUXILIARY QP WITH GIVEN OPTIMAL SOLUTION: */
|
||
|
/* 1) Setup bounds and constraints data structure. */
|
||
|
if ( bounds.setupAllFree( ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_INIT_FAILED );
|
||
|
|
||
|
if ( constraints.setupAllInactive( ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_INIT_FAILED );
|
||
|
|
||
|
/* 2) Setup optimal primal/dual solution for auxiliary QP. */
|
||
|
if ( setupAuxiliaryQPsolution( xOpt,yOpt ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_INIT_FAILED );
|
||
|
|
||
|
/* 3) Obtain linear independent working set for auxiliary QP. */
|
||
|
|
||
|
static Bounds auxiliaryBounds;
|
||
|
|
||
|
auxiliaryBounds.init( nV );
|
||
|
|
||
|
static Constraints auxiliaryConstraints;
|
||
|
|
||
|
auxiliaryConstraints.init( nC );
|
||
|
|
||
|
if ( obtainAuxiliaryWorkingSet( xOpt,yOpt,guessedBounds,guessedConstraints,
|
||
|
&auxiliaryBounds,&auxiliaryConstraints ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_INIT_FAILED );
|
||
|
|
||
|
/* 4) Setup working set of auxiliary QP and setup matrix factorisations. */
|
||
|
if ( setupTQfactorisation( ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_INIT_FAILED_TQ );
|
||
|
|
||
|
if ( setupAuxiliaryWorkingSet( &auxiliaryBounds,&auxiliaryConstraints,BT_TRUE ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_INIT_FAILED );
|
||
|
|
||
|
if ( ( getNAC( ) + getNFX( ) ) == 0 )
|
||
|
{
|
||
|
/* Factorise full Hessian if no bounds/constraints are active. */
|
||
|
if (hasCholesky == BT_FALSE)
|
||
|
if ( setupCholeskyDecomposition( ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_INIT_FAILED_CHOLESKY );
|
||
|
/* ... else we use user provided Cholesky factorization. At the moment
|
||
|
* we can do that only for cold-started solver. */
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Factorise projected Hessian if there active bounds/constraints. */
|
||
|
if ( setupCholeskyDecompositionProjected( ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_INIT_FAILED_CHOLESKY );
|
||
|
/* TODO: use user-supplied Hessian decomposition. R_Z = R * Z. */
|
||
|
}
|
||
|
|
||
|
/* 5) Store original QP formulation... */
|
||
|
real_t g_original[NVMAX];
|
||
|
real_t lb_original[NVMAX];
|
||
|
real_t ub_original[NVMAX];
|
||
|
real_t lbA_original[NCMAX_ALLOC];
|
||
|
real_t ubA_original[NCMAX_ALLOC];
|
||
|
|
||
|
for( i=0; i<nV; ++i )
|
||
|
{
|
||
|
g_original[i] = g[i];
|
||
|
lb_original[i] = lb[i];
|
||
|
ub_original[i] = ub[i];
|
||
|
}
|
||
|
|
||
|
for( i=0; i<nC; ++i )
|
||
|
{
|
||
|
lbA_original[i] = lbA[i];
|
||
|
ubA_original[i] = ubA[i];
|
||
|
}
|
||
|
|
||
|
/* ... and setup QP data of an auxiliary QP having an optimal solution
|
||
|
* as specified by the user (or xOpt = yOpt = 0, by default). */
|
||
|
if ( setupAuxiliaryQPgradient( ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_INIT_FAILED );
|
||
|
|
||
|
if ( setupAuxiliaryQPbounds( &auxiliaryBounds,&auxiliaryConstraints,BT_TRUE ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_INIT_FAILED );
|
||
|
|
||
|
status = QPS_AUXILIARYQPSOLVED;
|
||
|
|
||
|
|
||
|
/* III) SOLVE ACTUAL INITIAL QP: */
|
||
|
/* Use hotstart method to find the solution of the original initial QP,... */
|
||
|
returnValue returnvalue = hotstart( g_original,lb_original,ub_original,lbA_original,ubA_original, nWSR,0 );
|
||
|
|
||
|
|
||
|
/* ... check for infeasibility and unboundedness... */
|
||
|
if ( isInfeasible( ) == BT_TRUE )
|
||
|
return THROWERROR( RET_INIT_FAILED_INFEASIBILITY );
|
||
|
|
||
|
if ( isUnbounded( ) == BT_TRUE )
|
||
|
return THROWERROR( RET_INIT_FAILED_UNBOUNDEDNESS );
|
||
|
|
||
|
/* ... and internal errors. */
|
||
|
if ( ( returnvalue != SUCCESSFUL_RETURN ) && ( returnvalue != RET_MAX_NWSR_REACHED ) &&
|
||
|
( returnvalue != RET_INACCURATE_SOLUTION ) && ( returnvalue != RET_NO_SOLUTION ) )
|
||
|
return THROWERROR( RET_INIT_FAILED_HOTSTART );
|
||
|
|
||
|
|
||
|
/* stop runtime measurement */
|
||
|
if ( cputime != 0 )
|
||
|
*cputime = getCPUtime( ) - starttime;
|
||
|
|
||
|
if ( printlevel == PL_HIGH )
|
||
|
THROWINFO( RET_INIT_SUCCESSFUL );
|
||
|
|
||
|
return returnvalue;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* 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
|
||
|
*/
|
||
|
returnValue QProblem::obtainAuxiliaryWorkingSet( const real_t* const xOpt, const real_t* const yOpt,
|
||
|
const Bounds* const guessedBounds, const Constraints* const guessedConstraints,
|
||
|
Bounds* auxiliaryBounds, Constraints* auxiliaryConstraints
|
||
|
) const
|
||
|
{
|
||
|
int i = 0;
|
||
|
int nV = getNV( );
|
||
|
int nC = getNC( );
|
||
|
|
||
|
|
||
|
/* 1) Ensure that desiredBounds is allocated (and different from guessedBounds). */
|
||
|
if ( ( auxiliaryBounds == 0 ) || ( auxiliaryBounds == guessedBounds ) )
|
||
|
return THROWERROR( RET_INVALID_ARGUMENTS );
|
||
|
|
||
|
if ( ( auxiliaryConstraints == 0 ) || ( auxiliaryConstraints == guessedConstraints ) )
|
||
|
return THROWERROR( RET_INVALID_ARGUMENTS );
|
||
|
|
||
|
|
||
|
SubjectToStatus guessedStatus;
|
||
|
|
||
|
/* 2) Setup working set of bounds for auxiliary initial QP. */
|
||
|
if ( QProblemB::obtainAuxiliaryWorkingSet( xOpt,yOpt,guessedBounds, auxiliaryBounds ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_OBTAINING_WORKINGSET_FAILED );
|
||
|
|
||
|
/* 3) Setup working set of constraints for auxiliary initial QP. */
|
||
|
if ( guessedConstraints != 0 )
|
||
|
{
|
||
|
/* If an initial working set is specific, use it!
|
||
|
* Moreover, add all equality constraints if specified. */
|
||
|
for( i=0; i<nC; ++i )
|
||
|
{
|
||
|
guessedStatus = guessedConstraints->getStatus( 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; i<nC; ++i )
|
||
|
{
|
||
|
if ( Ax[i] <= lbA[i] + BOUNDTOL )
|
||
|
{
|
||
|
if ( auxiliaryConstraints->setupConstraint( 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<nC; ++i )
|
||
|
{
|
||
|
if ( yOpt[nV+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; i<nC; ++i )
|
||
|
{
|
||
|
/* Only 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 );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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; i<nV; ++i )
|
||
|
if ( ( bounds.getStatus( i ) == ST_UNDEFINED ) || ( auxiliaryBounds->getStatus( i ) == ST_UNDEFINED ) )
|
||
|
return THROWERROR( RET_UNKNOWN_BUG );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return THROWERROR( RET_INVALID_ARGUMENTS );
|
||
|
}
|
||
|
|
||
|
if ( auxiliaryConstraints != 0 )
|
||
|
{
|
||
|
for( i=0; i<nC; ++i )
|
||
|
if ( ( constraints.getStatus( i ) == ST_UNDEFINED ) || ( auxiliaryConstraints->getStatus( 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; i<nC; ++i )
|
||
|
{
|
||
|
if ( ( constraints.getStatus( i ) == ST_LOWER ) && ( auxiliaryConstraints->getStatus( 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; i<nV; ++i )
|
||
|
{
|
||
|
if ( ( bounds.getStatus( i ) == ST_LOWER ) && ( auxiliaryBounds->getStatus( 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; i<nV; ++i )
|
||
|
{
|
||
|
if ( ( bounds.getStatus( i ) == ST_INACTIVE ) && ( auxiliaryBounds->getStatus( 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; i<nC; ++i )
|
||
|
{
|
||
|
if ( ( auxiliaryConstraints->getStatus( 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; i<nV; ++i )
|
||
|
x[i] = xOpt[i];
|
||
|
|
||
|
for ( j=0; j<nC; ++j )
|
||
|
{
|
||
|
Ax[j] = 0.0;
|
||
|
|
||
|
for( i=0; i<nV; ++i )
|
||
|
Ax[j] += A[j*NVMAX + i] * x[i];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for( i=0; i<nV; ++i )
|
||
|
x[i] = 0.0;
|
||
|
|
||
|
for ( j=0; j<nC; ++j )
|
||
|
Ax[j] = 0.0;
|
||
|
}
|
||
|
|
||
|
if ( yOpt != 0 )
|
||
|
{
|
||
|
if ( yOpt != y )
|
||
|
for( i=0; i<nV+nC; ++i )
|
||
|
y[i] = yOpt[i];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for( i=0; i<nV+nC; ++i )
|
||
|
y[i] = 0.0;
|
||
|
}
|
||
|
|
||
|
return SUCCESSFUL_RETURN;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* s e t u p A u x i l i a r y Q P g r a d i e n t
|
||
|
*/
|
||
|
returnValue QProblem::setupAuxiliaryQPgradient( )
|
||
|
{
|
||
|
int i, j;
|
||
|
int nV = getNV( );
|
||
|
int nC = getNC( );
|
||
|
|
||
|
|
||
|
/* Setup gradient vector: g = -H*x + [Id A]'*[yB yC]. */
|
||
|
for ( i=0; i<nV; ++i )
|
||
|
{
|
||
|
/* Id'*yB */
|
||
|
g[i] = y[i];
|
||
|
|
||
|
/* A'*yC */
|
||
|
for ( j=0; j<nC; ++j )
|
||
|
g[i] += A[j*NVMAX + i] * y[nV+j];
|
||
|
|
||
|
/* -H*x */
|
||
|
for ( j=0; j<nV; ++j )
|
||
|
g[i] -= H[i*NVMAX + j] * x[j];
|
||
|
}
|
||
|
|
||
|
return SUCCESSFUL_RETURN;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* s e t u p A u x i l i a r y Q P b o u n d s
|
||
|
*/
|
||
|
returnValue QProblem::setupAuxiliaryQPbounds( const Bounds* const auxiliaryBounds,
|
||
|
const Constraints* const auxiliaryConstraints,
|
||
|
BooleanType useRelaxation
|
||
|
)
|
||
|
{
|
||
|
int i;
|
||
|
int nV = getNV( );
|
||
|
int nC = getNC( );
|
||
|
|
||
|
|
||
|
/* 1) Setup bound vectors. */
|
||
|
for ( i=0; i<nV; ++i )
|
||
|
{
|
||
|
switch ( bounds.getStatus( i ) )
|
||
|
{
|
||
|
case ST_INACTIVE:
|
||
|
if ( useRelaxation == BT_TRUE )
|
||
|
{
|
||
|
if ( bounds.getType( i ) == ST_EQUALITY )
|
||
|
{
|
||
|
lb[i] = x[i];
|
||
|
ub[i] = x[i];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* If a bound is inactive although it was supposed to be
|
||
|
* active by the auxiliaryBounds, it could not be added
|
||
|
* due to linear dependence. Thus set it "strongly inactive". */
|
||
|
if ( auxiliaryBounds->getStatus( 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; i<nC; ++i )
|
||
|
{
|
||
|
switch ( constraints.getStatus( i ) )
|
||
|
{
|
||
|
case ST_INACTIVE:
|
||
|
if ( useRelaxation == BT_TRUE )
|
||
|
{
|
||
|
if ( constraints.getType( i ) == ST_EQUALITY )
|
||
|
{
|
||
|
lbA[i] = Ax[i];
|
||
|
ubA[i] = Ax[i];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* If a constraint is inactive although it was supposed to be
|
||
|
* active by the auxiliaryConstraints, it could not be added
|
||
|
* due to linear dependence. Thus set it "strongly inactive". */
|
||
|
if ( auxiliaryConstraints->getStatus( 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<nZ; ++i )
|
||
|
wZ[i] = 0.0;
|
||
|
|
||
|
|
||
|
/* II) ADD NEW ACTIVE CONSTRAINT TO MATRIX T: */
|
||
|
/* 1) Add row [wZ wY] = aFR'*[Z Y] to the end of T: assign aFR. */
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
aFR[i] = A[number*NVMAX + ii];
|
||
|
}
|
||
|
|
||
|
/* calculate wZ */
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
for( j=0; j<nZ; ++j )
|
||
|
wZ[j] += aFR[i] * Q[ii*NVMAX + j];
|
||
|
}
|
||
|
|
||
|
/* 2) Calculate wY and store it directly into T. */
|
||
|
if ( nAC > 0 )
|
||
|
{
|
||
|
for( j=0; j<nAC; ++j )
|
||
|
T[nAC*NVMAX + tcol+j] = 0.0;
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
for( j=0; j<nAC; ++j )
|
||
|
T[nAC*NVMAX + tcol+j] += aFR[i] * Q[ii*NVMAX + nZ+j];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
real_t c, s;
|
||
|
|
||
|
if ( nZ > 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; j<nZ-1; ++j )
|
||
|
{
|
||
|
computeGivens( wZ[j+1],wZ[j], wZ[j+1],wZ[j],c,s );
|
||
|
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
applyGivens( c,s,Q[ii*NVMAX + 1+j],Q[ii*NVMAX + j], Q[ii*NVMAX + 1+j],Q[ii*NVMAX + j] );
|
||
|
}
|
||
|
|
||
|
if ( ( updateCholesky == BT_TRUE ) && ( hessianType != HST_IDENTITY ) )
|
||
|
{
|
||
|
for( i=0; i<=j+1; ++i )
|
||
|
applyGivens( c,s,R[i*NVMAX + 1+j],R[i*NVMAX + j], R[i*NVMAX + 1+j],R[i*NVMAX + j] );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
T[nAC*NVMAX + tcol-1] = wZ[nZ-1];
|
||
|
|
||
|
|
||
|
if ( ( updateCholesky == BT_TRUE ) && ( hessianType != HST_IDENTITY ) )
|
||
|
{
|
||
|
/* III) RESTORE TRIANGULAR FORM OF R:
|
||
|
* Use row-wise Givens rotations to restore upper triangular form of R. */
|
||
|
for( i=0; i<nZ-1; ++i )
|
||
|
{
|
||
|
computeGivens( R[i*NVMAX + i],R[(1+i)*NVMAX + i], R[i*NVMAX + i],R[(1+i)*NVMAX + i],c,s );
|
||
|
|
||
|
for( j=(1+i); j<(nZ-1); ++j ) /* last column of R is thrown away */
|
||
|
applyGivens( c,s,R[i*NVMAX + j],R[(1+i)*NVMAX + j], R[i*NVMAX + j],R[(1+i)*NVMAX + j] );
|
||
|
}
|
||
|
/* last column of R is thrown away */
|
||
|
for( i=0; i<nZ; ++i )
|
||
|
R[i*NVMAX + nZ-1] = 0.0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* IV) UPDATE INDICES */
|
||
|
if ( constraints.moveInactiveToActive( number,C_status ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_ADDCONSTRAINT_FAILED );
|
||
|
|
||
|
|
||
|
return SUCCESSFUL_RETURN;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* a d d C o n s t r a i n t _ c h e c k L I
|
||
|
*/
|
||
|
returnValue QProblem::addConstraint_checkLI( int number )
|
||
|
{
|
||
|
int i, j, jj;
|
||
|
int nFR = getNFR( );
|
||
|
int nZ = getNZ( );
|
||
|
|
||
|
int FR_idx[NVMAX];
|
||
|
if ( bounds.getFree( )->getNumberArray( FR_idx ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_INDEXLIST_CORRUPTED );
|
||
|
|
||
|
/* Check if constraint <number> is linearly independent from the
|
||
|
the active ones (<=> is element of null space of Afr). */
|
||
|
real_t sum;
|
||
|
|
||
|
for( i=0; i<nZ; ++i )
|
||
|
{
|
||
|
sum = 0.0;
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
sum += Q[jj*NVMAX + i] * A[number*NVMAX + jj];
|
||
|
}
|
||
|
|
||
|
if ( getAbs( sum ) > 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; i<nAC; ++i )
|
||
|
{
|
||
|
xiC_TMP[i] = 0.0;
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
xiC_TMP[i] += Q[jj*NVMAX + nZ+i] * A[number*NVMAX + jj];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for( i=0; i<nAC; ++i )
|
||
|
{
|
||
|
xiC_TMP[i] = 0.0;
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
xiC_TMP[i] -= Q[jj*NVMAX + nZ+i] * A[number*NVMAX + jj];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( backsolveT( xiC_TMP, BT_TRUE, xiC ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_ENSURELI_FAILED_TQ );
|
||
|
}
|
||
|
|
||
|
/* 3) Calculate xiB. */
|
||
|
int AC_idx[NCMAX_ALLOC];
|
||
|
if ( constraints.getActive( )->getNumberArray( AC_idx ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_ENSURELI_FAILED );
|
||
|
|
||
|
if ( C_status == ST_LOWER )
|
||
|
{
|
||
|
for( i=0; i<nFX; ++i )
|
||
|
{
|
||
|
ii = FX_idx[i];
|
||
|
xiB[i] = A[number*NVMAX + ii];
|
||
|
|
||
|
for( j=0; j<nAC; ++j )
|
||
|
{
|
||
|
jj = AC_idx[j];
|
||
|
xiB[i] -= A[jj*NVMAX + ii] * xiC[j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for( i=0; i<nFX; ++i )
|
||
|
{
|
||
|
ii = FX_idx[i];
|
||
|
xiB[i] = -A[number*NVMAX + ii];
|
||
|
|
||
|
for( j=0; j<nAC; ++j )
|
||
|
{
|
||
|
jj = AC_idx[j];
|
||
|
xiB[i] -= A[jj*NVMAX + ii] * xiC[j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* III) DETERMINE CONSTRAINT/BOUND TO BE REMOVED. */
|
||
|
real_t y_min = INFTY * INFTY;
|
||
|
int y_min_number = -1;
|
||
|
BooleanType y_min_isBound = BT_FALSE;
|
||
|
|
||
|
/* 1) Constraints. */
|
||
|
for( i=0; i<nAC; ++i )
|
||
|
{
|
||
|
ii = AC_idx[i];
|
||
|
|
||
|
if ( constraints.getStatus( ii ) == ST_LOWER )
|
||
|
{
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
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<nFX; ++i )
|
||
|
{
|
||
|
ii = FX_idx[i];
|
||
|
|
||
|
if ( bounds.getStatus( ii ) == ST_LOWER )
|
||
|
{
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
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; i<nAC; ++i )
|
||
|
{
|
||
|
ii = AC_idx[i];
|
||
|
y[nV+ii] -= y_min * xiC[i];
|
||
|
}
|
||
|
for( i=0; i<nFX; ++i )
|
||
|
{
|
||
|
ii = FX_idx[i];
|
||
|
y[ii] -= y_min * xiB[i];
|
||
|
}
|
||
|
|
||
|
/* ... also for newly active constraint... */
|
||
|
if ( C_status == ST_LOWER )
|
||
|
y[nV+number] = y_min;
|
||
|
else
|
||
|
y[nV+number] = -y_min;
|
||
|
|
||
|
/* ... and for constraint to be removed. */
|
||
|
if ( y_min_isBound == BT_TRUE )
|
||
|
{
|
||
|
#ifdef PC_DEBUG
|
||
|
sprintf( messageString,"bound no. %d.",y_min_number );
|
||
|
getGlobalMessageHandler( )->throwInfo( 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<nFR; ++i )
|
||
|
w[i] = Q[FR_idx[nFR-1]*NVMAX + i];
|
||
|
|
||
|
|
||
|
/* 2) Use column-wise Givens rotations to restore reverse triangular form
|
||
|
* of the first row of T, simultanenous change of Q (i.e. Z) and R. */
|
||
|
real_t c, s;
|
||
|
|
||
|
for( j=0; j<nZ-1; ++j )
|
||
|
{
|
||
|
computeGivens( w[j+1],w[j], w[j+1],w[j],c,s );
|
||
|
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
applyGivens( c,s,Q[ii*NVMAX + 1+j],Q[ii*NVMAX + j], Q[ii*NVMAX + 1+j],Q[ii*NVMAX + j] );
|
||
|
}
|
||
|
|
||
|
if ( ( updateCholesky == BT_TRUE ) && ( hessianType != HST_IDENTITY ) )
|
||
|
{
|
||
|
for( i=0; i<=j+1; ++i )
|
||
|
applyGivens( c,s,R[i*NVMAX + 1+j],R[i*NVMAX + j], R[i*NVMAX + 1+j],R[i*NVMAX + j] );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( nAC > 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<nAC; ++i )
|
||
|
tmp[i] = 0.0;
|
||
|
|
||
|
{
|
||
|
j = nZ-1;
|
||
|
|
||
|
computeGivens( w[j+1],w[j], w[j+1],w[j],c,s );
|
||
|
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
applyGivens( c,s,Q[ii*NVMAX + 1+j],Q[ii*NVMAX + j], Q[ii*NVMAX + 1+j],Q[ii*NVMAX + j] );
|
||
|
}
|
||
|
|
||
|
applyGivens( c,s,T[(nAC-1)*NVMAX + tcol],tmp[nAC-1], tmp[nAC-1],T[(nAC-1)*NVMAX + tcol] );
|
||
|
}
|
||
|
|
||
|
for( j=nZ; j<nFR-1; ++j )
|
||
|
{
|
||
|
computeGivens( w[j+1],w[j], w[j+1],w[j],c,s );
|
||
|
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
applyGivens( c,s,Q[ii*NVMAX + 1+j],Q[ii*NVMAX + j], Q[ii*NVMAX + 1+j],Q[ii*NVMAX + j] );
|
||
|
}
|
||
|
|
||
|
for( i=(nFR-2-j); i<nAC; ++i )
|
||
|
applyGivens( c,s,T[i*NVMAX + 1+tcol-nZ+j],tmp[i], tmp[i],T[i*NVMAX + 1+tcol-nZ+j] );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( ( updateCholesky == BT_TRUE ) && ( hessianType != HST_IDENTITY ) )
|
||
|
{
|
||
|
/* III) RESTORE TRIANGULAR FORM OF R:
|
||
|
* use row-wise Givens rotations to restore upper triangular form of R */
|
||
|
for( i=0; i<nZ-1; ++i )
|
||
|
{
|
||
|
computeGivens( R[i*NVMAX + i],R[(1+i)*NVMAX + i], R[i*NVMAX + i],R[(1+i)*NVMAX + i],c,s );
|
||
|
|
||
|
for( j=(1+i); j<nZ-1; ++j ) /* last column of R is thrown away */
|
||
|
applyGivens( c,s,R[i*NVMAX + j],R[(1+i)*NVMAX + j], R[i*NVMAX + j],R[(1+i)*NVMAX + j] );
|
||
|
}
|
||
|
/* last column of R is thrown away */
|
||
|
for( i=0; i<nZ; ++i )
|
||
|
R[i*NVMAX + nZ-1] = 0.0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* IV) UPDATE INDICES */
|
||
|
if ( bounds.moveFreeToFixed( number,B_status ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_ADDBOUND_FAILED );
|
||
|
|
||
|
return SUCCESSFUL_RETURN;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* a d d B o u n d _ c h e c k L I
|
||
|
*/
|
||
|
returnValue QProblem::addBound_checkLI( int number )
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
/* some definitions */
|
||
|
int nZ = getNZ( );
|
||
|
|
||
|
/* Check if constraint <number> is linearly independent from the
|
||
|
the active ones (<=> is element of null space of Afr). */
|
||
|
for( i=0; i<nZ; ++i )
|
||
|
{
|
||
|
if ( getAbs( Q[number*NVMAX + 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<nAC; ++i )
|
||
|
xiC_TMP[i] = Q[number*NVMAX + nZ+i];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for( i=0; i<nAC; ++i )
|
||
|
xiC_TMP[i] = -Q[number*NVMAX + nZ+i];
|
||
|
}
|
||
|
|
||
|
if ( backsolveT( xiC_TMP, BT_TRUE, xiC ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_ENSURELI_FAILED_TQ );
|
||
|
}
|
||
|
|
||
|
/* 3) Calculate xiB. */
|
||
|
for( i=0; i<nFX; ++i )
|
||
|
{
|
||
|
ii = FX_idx[i];
|
||
|
|
||
|
xiB[i] = 0.0;
|
||
|
for( j=0; j<nAC; ++j )
|
||
|
{
|
||
|
jj = AC_idx[j];
|
||
|
xiB[i] -= A[jj*NVMAX + ii] * xiC[j];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* III) DETERMINE CONSTRAINT/BOUND TO BE REMOVED. */
|
||
|
real_t y_min = INFTY * INFTY;
|
||
|
int y_min_number = -1;
|
||
|
BooleanType y_min_isBound = BT_FALSE;
|
||
|
|
||
|
/* 1) Constraints. */
|
||
|
for( i=0; i<nAC; ++i )
|
||
|
{
|
||
|
ii = AC_idx[i];
|
||
|
|
||
|
if ( constraints.getStatus( ii ) == ST_LOWER )
|
||
|
{
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
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<nFX; ++i )
|
||
|
{
|
||
|
ii = FX_idx[i];
|
||
|
|
||
|
if ( bounds.getStatus( ii ) == ST_LOWER )
|
||
|
{
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
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; i<nAC; ++i )
|
||
|
{
|
||
|
ii = AC_idx[i];
|
||
|
y[nV+ii] -= y_min * xiC[i];
|
||
|
}
|
||
|
for( i=0; i<nFX; ++i )
|
||
|
{
|
||
|
ii = FX_idx[i];
|
||
|
y[ii] -= y_min * xiB[i];
|
||
|
}
|
||
|
|
||
|
/* ... also for newly active bound ... */
|
||
|
if ( B_status == ST_LOWER )
|
||
|
y[number] = y_min;
|
||
|
else
|
||
|
y[number] = -y_min;
|
||
|
|
||
|
/* ... and for bound to be removed. */
|
||
|
if ( y_min_isBound == BT_TRUE )
|
||
|
{
|
||
|
#ifdef PC_DEBUG
|
||
|
sprintf( messageString,"bound no. %d.",y_min_number );
|
||
|
getGlobalMessageHandler( )->throwInfo( 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 <number>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<nAC; ++i )
|
||
|
for( j=(nAC-i-1); j<nAC; ++j )
|
||
|
T[(i-1)*NVMAX + tcol+j] = T[i*NVMAX + tcol+j];
|
||
|
/* gimmick: write zeros into the last row of T */
|
||
|
for( j=0; j<nAC; ++j )
|
||
|
T[(nAC-1)*NVMAX + tcol+j] = 0.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. Y). */
|
||
|
real_t c, s;
|
||
|
|
||
|
for( j=(nAC-2-number_idx); j>=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<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
applyGivens( c,s,Q[ii*NVMAX + nZ+1+j],Q[ii*NVMAX + nZ+j], Q[ii*NVMAX + nZ+1+j],Q[ii*NVMAX + nZ+j] );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* gimmick: write zeros into the last row of T */
|
||
|
for( j=0; j<nAC; ++j )
|
||
|
T[(nAC-1)*NVMAX + tcol+j] = 0.0;
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( ( updateCholesky == BT_TRUE ) && ( hessianType != HST_IDENTITY ) )
|
||
|
{
|
||
|
/* III) UPDATE CHOLESKY DECOMPOSITION,
|
||
|
* calculate new additional column (i.e. [r sqrt(rho2)]')
|
||
|
* of the Cholesky factor R. */
|
||
|
real_t Hz[NVMAX];
|
||
|
for ( i=0; i<nFR; ++i )
|
||
|
Hz[i] = 0.0;
|
||
|
real_t rho2 = 0.0;
|
||
|
|
||
|
/* 1) Calculate Hz = H*z, where z is the new rightmost column of Z
|
||
|
* (i.e. the old leftmost column of Y). */
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
Hz[i] += H[jj*NVMAX + FR_idx[i]] * Q[jj*NVMAX + nZ];
|
||
|
}
|
||
|
|
||
|
if ( nZ > 0 )
|
||
|
{
|
||
|
real_t ZHz[NVMAX];
|
||
|
for ( i=0; i<nZ; ++i )
|
||
|
ZHz[i] = 0.0;
|
||
|
real_t r[NVMAX];
|
||
|
|
||
|
/* 2) Calculate ZHz = Z'*Hz (old Z). */
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
|
||
|
for( i=0; i<nZ; ++i )
|
||
|
ZHz[i] += Q[jj*NVMAX + i] * Hz[j];
|
||
|
}
|
||
|
|
||
|
/* 3) Calculate r = R^-T * ZHz. */
|
||
|
if ( backsolveR( ZHz,BT_TRUE,r ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_REMOVECONSTRAINT_FAILED );
|
||
|
|
||
|
/* 4) Calculate rho2 = rho^2 = z'*Hz - r'*r
|
||
|
* and store r into R. */
|
||
|
for( i=0; i<nZ; ++i )
|
||
|
{
|
||
|
rho2 -= r[i]*r[i];
|
||
|
R[i*NVMAX + nZ] = r[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
rho2 += Q[FR_idx[j]*NVMAX + nZ] * Hz[j];
|
||
|
|
||
|
/* 5) Store rho into R. */
|
||
|
if ( rho2 > 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 <nFR+1>th UNITY VECOTR TO Q. */
|
||
|
int nnFRp1 = FR_idx[nFR];
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
Q[ii*NVMAX + nFR] = 0.0;
|
||
|
Q[nnFRp1*NVMAX + i] = 0.0;
|
||
|
}
|
||
|
Q[nnFRp1*NVMAX + nFR] = 1.0;
|
||
|
|
||
|
if ( nAC > 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<nAC; ++i )
|
||
|
{
|
||
|
ii = AC_idx[i];
|
||
|
tmp[i] = A[ii*NVMAX + number];
|
||
|
}
|
||
|
|
||
|
|
||
|
/* II) RESTORE TRIANGULAR FORM OF T,
|
||
|
* use column-wise Givens rotations to restore reverse triangular form
|
||
|
* of T = [T A(:,number)], simultanenous change of Q (i.e. Y and Z). */
|
||
|
real_t c, s;
|
||
|
|
||
|
for( j=(nAC-1); j>=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<nAC; ++i )
|
||
|
applyGivens( c,s,tmp[i],T[i*NVMAX + tcol+j],T[i*NVMAX + tcol+j],tmp[i] );
|
||
|
|
||
|
for( i=0; i<=nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
/* nZ+1+nAC = nFR+1 / nZ+(1) = nZ+1 */
|
||
|
applyGivens( c,s,Q[ii*NVMAX + nZ+1+j],Q[ii*NVMAX + nZ+j],Q[ii*NVMAX + nZ+1+j],Q[ii*NVMAX + nZ+j] );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( ( updateCholesky == BT_TRUE ) && ( hessianType != HST_IDENTITY ) )
|
||
|
{
|
||
|
/* III) UPDATE CHOLESKY DECOMPOSITION,
|
||
|
* calculate new additional column (i.e. [r sqrt(rho2)]')
|
||
|
* of the Cholesky factor R: */
|
||
|
real_t z2 = Q[nnFRp1*NVMAX + nZ];
|
||
|
real_t rho2 = H[nnFRp1*NVMAX + nnFRp1]*z2*z2; /* rho2 = h2*z2*z2 */
|
||
|
|
||
|
if ( nFR > 0 )
|
||
|
{
|
||
|
real_t Hz[NVMAX];
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
Hz[i] = 0.0;
|
||
|
/* 1) Calculate R'*r = Zfr'*Hfr*z1 + z2*Zfr'*h1 =: Zfr'*Hz + z2*Zfr'*h1 =: rhs and
|
||
|
* rho2 = z1'*Hfr*z1 + 2*z2*h1'*z1 + h2*z2^2 - r'*r =: z1'*Hz + 2*z2*h1'*z1 + h2*z2^2 - r'r */
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
/* H * z1 */
|
||
|
Hz[i] += H[jj*NVMAX + ii] * Q[jj*NVMAX + nZ];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( nZ > 0 )
|
||
|
{
|
||
|
real_t r[NVMAX];
|
||
|
real_t rhs[NVMAX];
|
||
|
for( i=0; i<nZ; ++i )
|
||
|
rhs[i] = 0.0;
|
||
|
|
||
|
/* 2) Calculate rhs. */
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
for( i=0; i<nZ; ++i )
|
||
|
/* Zfr' * ( Hz + z2*h1 ) */
|
||
|
rhs[i] += Q[jj*NVMAX + i] * ( Hz[j] + z2 * H[nnFRp1*NVMAX + jj] );
|
||
|
}
|
||
|
|
||
|
/* 3) Calculate r = R^-T * rhs. */
|
||
|
if ( backsolveR( rhs,BT_TRUE,BT_TRUE,r ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_REMOVEBOUND_FAILED );
|
||
|
|
||
|
/* 4) Calculate rho2 = rho^2 = z'*Hz - r'*r
|
||
|
* and store r into R. */
|
||
|
for( i=0; i<nZ; ++i )
|
||
|
{
|
||
|
rho2 -= r[i]*r[i];
|
||
|
R[i*NVMAX + nZ] = r[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
/* z1' * ( Hz + 2*z2*h1 ) */
|
||
|
rho2 += Q[jj*NVMAX + nZ] * ( Hz[j] + 2.0*z2*H[nnFRp1*NVMAX + jj] );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* 5) Store rho into R. */
|
||
|
if ( rho2 > 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<nR; ++j )
|
||
|
sum -= R[i*NVMAX + j] * a[j];
|
||
|
|
||
|
if ( getAbs( R[i*NVMAX + i] ) > 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<nR; ++i )
|
||
|
{
|
||
|
sum = b[i];
|
||
|
|
||
|
for( j=0; j<i; ++j )
|
||
|
sum -= R[j*NVMAX + i] * a[j];
|
||
|
|
||
|
if ( getAbs( R[i*NVMAX + 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<nT; ++i )
|
||
|
{
|
||
|
sum = b[i];
|
||
|
for( j=0; j<i; ++j )
|
||
|
sum -= T[i*NVMAX + sizeT-1-j] * a[nT-1-j];
|
||
|
|
||
|
if ( getAbs( T[i*NVMAX + sizeT-1-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<nT; ++i )
|
||
|
{
|
||
|
sum = b[i];
|
||
|
for( j=0; j<i; ++j )
|
||
|
sum -= T[(nT-1-j)*NVMAX + tcol+i] * a[nT-1-j];
|
||
|
|
||
|
if ( getAbs( T[(nT-1-i)*NVMAX + tcol+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<nC; ++i )
|
||
|
{
|
||
|
/* if lower constraints' bounds do not exist, shift them to -infinity */
|
||
|
if ( lbA_new != 0 )
|
||
|
delta_lbA[i] = lbA_new[i] - lbA[i];
|
||
|
else
|
||
|
delta_lbA[i] = -INFTY - lbA[i];
|
||
|
}
|
||
|
|
||
|
for( i=0; i<nC; ++i )
|
||
|
{
|
||
|
/* if upper constraints' bounds do not exist, shift them to infinity */
|
||
|
if ( ubA_new != 0 )
|
||
|
delta_ubA[i] = ubA_new[i] - ubA[i];
|
||
|
else
|
||
|
delta_ubA[i] = INFTY - ubA[i];
|
||
|
}
|
||
|
|
||
|
/* 2) Determine if active constraints' bounds are to be shifted. */
|
||
|
Delta_bC_isZero = BT_TRUE;
|
||
|
|
||
|
for ( i=0; i<nAC; ++i )
|
||
|
{
|
||
|
ii = AC_idx[i];
|
||
|
|
||
|
if ( ( getAbs( delta_lbA[ii] ) > 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<nFR; ++i )
|
||
|
{
|
||
|
delta_xFR[i] = 0.0;
|
||
|
HMX_delta_xFX[i] = 0.0;
|
||
|
YFR_delta_xFRy[i] = 0.0;
|
||
|
ZFR_delta_xFRz[i] = 0.0;
|
||
|
HFR_YFR_delta_xFRy[i] = 0.0;
|
||
|
}
|
||
|
|
||
|
real_t delta_xFRy[NCMAX_ALLOC];
|
||
|
real_t delta_xFRz[NVMAX];
|
||
|
for( i=0; i<nZ; ++i )
|
||
|
delta_xFRz[i] = 0.0;
|
||
|
|
||
|
|
||
|
/* I) DETERMINE delta_xFX */
|
||
|
if ( nFX > 0 )
|
||
|
{
|
||
|
for( i=0; i<nFX; ++i )
|
||
|
{
|
||
|
ii = FX_idx[i];
|
||
|
|
||
|
if ( bounds.getStatus( ii ) == ST_LOWER )
|
||
|
delta_xFX[i] = delta_lb[ii];
|
||
|
else
|
||
|
delta_xFX[i] = delta_ub[ii];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* II) DETERMINE delta_xFR */
|
||
|
if ( nFR > 0 )
|
||
|
{
|
||
|
/* 1) Determine delta_xFRy. */
|
||
|
if ( nAC > 0 )
|
||
|
{
|
||
|
if ( ( Delta_bC_isZero == BT_TRUE ) && ( Delta_bB_isZero == BT_TRUE ) )
|
||
|
{
|
||
|
for( i=0; i<nAC; ++i )
|
||
|
delta_xFRy[i] = 0.0;
|
||
|
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
delta_xFR[i] = 0.0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* auxillary variable */
|
||
|
real_t delta_xFRy_TMP[NCMAX_ALLOC];
|
||
|
|
||
|
for( i=0; i<nAC; ++i )
|
||
|
{
|
||
|
ii = AC_idx[i];
|
||
|
|
||
|
if ( constraints.getStatus( ii ) == ST_LOWER )
|
||
|
delta_xFRy_TMP[i] = delta_lbA[ii];
|
||
|
else
|
||
|
delta_xFRy_TMP[i] = delta_ubA[ii];
|
||
|
|
||
|
if ( Delta_bB_isZero == BT_FALSE )
|
||
|
{
|
||
|
for( j=0; j<nFX; ++j )
|
||
|
{
|
||
|
jj = FX_idx[j];
|
||
|
delta_xFRy_TMP[i] -= A[ii*NVMAX + jj] * delta_xFX[j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( backsolveT( delta_xFRy_TMP, BT_FALSE, delta_xFRy ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_STEPDIRECTION_FAILED_TQ );
|
||
|
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
for( j=0; j<nAC; ++j )
|
||
|
YFR_delta_xFRy[i] += Q[ii*NVMAX + nZ+j] * delta_xFRy[j];
|
||
|
|
||
|
/* delta_xFR = YFR*delta_xFRy (+ ZFR*delta_xFRz) */
|
||
|
delta_xFR[i] = YFR_delta_xFRy[i];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* 2) Determine delta_xFRz. */
|
||
|
if ( hessianType == HST_IDENTITY )
|
||
|
{
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
for( i=0; i<nZ; ++i )
|
||
|
delta_xFRz[i] -= Q[jj*NVMAX + i] * delta_g[jj];
|
||
|
}
|
||
|
|
||
|
if ( nZ > 0 )
|
||
|
{
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
for( j=0; j<nZ; ++j )
|
||
|
ZFR_delta_xFRz[i] += Q[ii*NVMAX + j] * delta_xFRz[j];
|
||
|
|
||
|
delta_xFR[i] += ZFR_delta_xFRz[i];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( Delta_bB_isZero == BT_FALSE )
|
||
|
{
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
for( j=0; j<nFX; ++j )
|
||
|
{
|
||
|
jj = FX_idx[j];
|
||
|
HMX_delta_xFX[i] += H[ii*NVMAX + jj] * delta_xFX[j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( nAC > 0 )
|
||
|
{
|
||
|
if ( ( Delta_bC_isZero == BT_FALSE ) || ( Delta_bB_isZero == BT_FALSE ) )
|
||
|
{
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
HFR_YFR_delta_xFRy[i] += H[ii*NVMAX + jj] * YFR_delta_xFRy[j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( nZ > 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<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
delta_xFRz_RHS[j] = delta_g[jj] + HFR_YFR_delta_xFRy[j] + HMX_delta_xFX[j];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( ( nAC == 0 ) && ( Delta_bB_isZero == BT_TRUE ) )
|
||
|
{
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
delta_xFRz_RHS[j] = delta_g[jj];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( nAC > 0 ) /* => Delta_bB_isZero == BT_TRUE, as BT_FALSE would imply nFX>0 */
|
||
|
{
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
delta_xFRz_RHS[j] = delta_g[jj] + HFR_YFR_delta_xFRy[j];
|
||
|
}
|
||
|
}
|
||
|
else /* Delta_bB_isZero == BT_FALSE, as nAC==0 */
|
||
|
{
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
delta_xFRz_RHS[j] = delta_g[jj] + HMX_delta_xFX[j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
for( i=0; i<nZ; ++i )
|
||
|
delta_xFRz[i] -= Q[jj*NVMAX + i] * delta_xFRz_RHS[j];
|
||
|
}
|
||
|
|
||
|
|
||
|
if ( backsolveR( delta_xFRz,BT_TRUE,delta_xFRz_TMP ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_STEPDIRECTION_FAILED_CHOLESKY );
|
||
|
|
||
|
if ( backsolveR( delta_xFRz_TMP,BT_FALSE,delta_xFRz ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_STEPDIRECTION_FAILED_CHOLESKY );
|
||
|
|
||
|
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
for( j=0; j<nZ; ++j )
|
||
|
ZFR_delta_xFRz[i] += Q[ii*NVMAX + j] * delta_xFRz[j];
|
||
|
|
||
|
delta_xFR[i] += ZFR_delta_xFRz[i];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* III) DETERMINE delta_yAC */
|
||
|
if ( nAC > 0 ) /* => ( nFR = nZ + nAC > 0 ) */
|
||
|
{
|
||
|
/* auxiliary variables */
|
||
|
real_t delta_yAC_TMP[NCMAX_ALLOC];
|
||
|
for( i=0; i<nAC; ++i )
|
||
|
delta_yAC_TMP[i] = 0.0;
|
||
|
real_t delta_yAC_RHS[NVMAX];
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
delta_yAC_RHS[i] = 0.0;
|
||
|
|
||
|
if ( hessianType == HST_IDENTITY )
|
||
|
{
|
||
|
/* delta_yAC = (T')^-1 * ( Yfr*delta_gFR + delta_xFRy ) */
|
||
|
for( j=0; j<nAC; ++j )
|
||
|
{
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
delta_yAC_TMP[j] += Q[ii*NVMAX + nZ+j] * delta_g[ii];
|
||
|
}
|
||
|
|
||
|
delta_yAC_TMP[j] += delta_xFRy[j];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( ( Delta_bC_isZero == BT_TRUE ) && ( Delta_bB_isZero == BT_TRUE ) )
|
||
|
{
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
delta_yAC_RHS[i] = delta_g[ii];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
delta_yAC_RHS[i] = HFR_YFR_delta_xFRy[i] + delta_g[ii];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( nZ > 0 )
|
||
|
{
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
delta_yAC_RHS[i] += H[ii*NVMAX + jj] * ZFR_delta_xFRz[j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( nFX > 0 )
|
||
|
{
|
||
|
if ( Delta_bB_isZero == BT_FALSE )
|
||
|
{
|
||
|
for( i=0; i<nFR; ++i )
|
||
|
delta_yAC_RHS[i] += HMX_delta_xFX[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for( i=0; i<nAC; ++i)
|
||
|
{
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
delta_yAC_TMP[i] += Q[jj*NVMAX + nZ+i] * delta_yAC_RHS[j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( backsolveT( delta_yAC_TMP,BT_TRUE,delta_yAC ) != SUCCESSFUL_RETURN )
|
||
|
return THROWERROR( RET_STEPDIRECTION_FAILED_TQ );
|
||
|
}
|
||
|
|
||
|
|
||
|
/* IV) DETERMINE delta_yFX */
|
||
|
if ( nFX > 0 )
|
||
|
{
|
||
|
for( i=0; i<nFX; ++i )
|
||
|
{
|
||
|
ii = FX_idx[i];
|
||
|
|
||
|
delta_yFX[i] = delta_g[ii];
|
||
|
|
||
|
for( j=0; j<nAC; ++j )
|
||
|
{
|
||
|
jj = AC_idx[j];
|
||
|
delta_yFX[i] -= A[jj*NVMAX + ii] * delta_yAC[j];
|
||
|
}
|
||
|
|
||
|
if ( hessianType == HST_IDENTITY )
|
||
|
{
|
||
|
delta_yFX[i] += delta_xFX[i];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for( j=0; j<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
delta_yFX[i] += H[ii*NVMAX + jj] * delta_xFR[j];
|
||
|
}
|
||
|
|
||
|
if ( Delta_bB_isZero == BT_FALSE )
|
||
|
{
|
||
|
for( j=0; j<nFX; ++j )
|
||
|
{
|
||
|
jj = FX_idx[j];
|
||
|
delta_yFX[i] += H[ii*NVMAX + jj] * delta_xFX[j];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return SUCCESSFUL_RETURN;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* 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
|
||
|
*/
|
||
|
returnValue QProblem::hotstart_determineStepLength( 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_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,
|
||
|
real_t* const delta_Ax, int& BC_idx, SubjectToStatus& BC_status, BooleanType& BC_isBound
|
||
|
)
|
||
|
{
|
||
|
int i, j, ii, jj;
|
||
|
int nV = getNV( );
|
||
|
int nC = getNC( );
|
||
|
int nFR = getNFR( );
|
||
|
int nFX = getNFX( );
|
||
|
int nAC = getNAC( );
|
||
|
int nIAC = getNIAC( );
|
||
|
|
||
|
/* initialise maximum steplength array */
|
||
|
real_t maxStepLength[2*(NVMAX+NCMAX_ALLOC)];
|
||
|
for ( i=0; i<2*(nV+nC); ++i )
|
||
|
maxStepLength[i] = 1.0;
|
||
|
|
||
|
|
||
|
/* I) DETERMINE MAXIMUM DUAL STEPLENGTH: */
|
||
|
/* 1) Ensure that active dual constraints' bounds remain valid
|
||
|
* (ignoring inequality constraints). */
|
||
|
for( i=0; i<nAC; ++i )
|
||
|
{
|
||
|
ii = AC_idx[i];
|
||
|
|
||
|
if ( constraints.getType( ii ) != ST_EQUALITY )
|
||
|
{
|
||
|
if ( constraints.getStatus( ii ) == ST_LOWER )
|
||
|
{
|
||
|
/* active lower 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;
|
||
|
}
|
||
|
}
|
||
|
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<nFX; ++i )
|
||
|
{
|
||
|
ii = FX_idx[i];
|
||
|
|
||
|
if ( bounds.getType( ii ) != ST_EQUALITY )
|
||
|
{
|
||
|
if ( bounds.getStatus( ii ) == ST_LOWER )
|
||
|
{
|
||
|
/* active lower bounds */
|
||
|
if ( delta_yFX[i] < -ZERO )
|
||
|
{
|
||
|
if ( y[ii] > 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<nFR; ++j )
|
||
|
{
|
||
|
jj = FR_idx[j];
|
||
|
delta_x[jj] = delta_xFR[j];
|
||
|
}
|
||
|
for( j=0; j<nFX; ++j )
|
||
|
{
|
||
|
jj = FX_idx[j];
|
||
|
delta_x[jj] = delta_xFX[j];
|
||
|
}
|
||
|
|
||
|
for( i=0; i<nIAC; ++i )
|
||
|
{
|
||
|
ii = IAC_idx[i];
|
||
|
|
||
|
if ( constraints.getType( ii ) != ST_UNBOUNDED )
|
||
|
{
|
||
|
delta_Ax[ii] = 0.0;
|
||
|
for( j=0; j<nV; ++j )
|
||
|
delta_Ax[ii] += A[ii*NVMAX + j] * delta_x[j]; // POSSIBLE SPEEDUP!
|
||
|
|
||
|
/* inactive lower constraints' bounds */
|
||
|
if ( constraints.isNoLower( ) == BT_FALSE )
|
||
|
{
|
||
|
if ( delta_lbA[ii] > 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<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
if ( bounds.getType( ii ) != ST_UNBOUNDED )
|
||
|
if ( delta_lb[ii] > 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<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
if ( bounds.getType( ii ) != ST_UNBOUNDED )
|
||
|
if ( delta_ub[ii] < delta_xFR[i] )
|
||
|
{
|
||
|
if ( x[ii] < ub[ii] )
|
||
|
maxStepLength[nV+nC+ii] = ( x[ii] - ub[ii] ) / ( delta_ub[ii] - delta_xFR[i] );
|
||
|
else
|
||
|
maxStepLength[nV+nC+ii] = 0.0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* III) DETERMINE MAXIMUM HOMOTOPY STEPLENGTH */
|
||
|
real_t tau_new = 1.0;
|
||
|
|
||
|
BC_idx = 0;
|
||
|
BC_status = ST_UNDEFINED;
|
||
|
BC_isBound = BT_FALSE;
|
||
|
|
||
|
for ( i=0; i<nV; ++i )
|
||
|
{
|
||
|
/* 1) Consider lower/dual blocking bounds. */
|
||
|
if ( maxStepLength[i] < tau_new )
|
||
|
{
|
||
|
tau_new = maxStepLength[i];
|
||
|
BC_idx = i;
|
||
|
BC_isBound = BT_TRUE;
|
||
|
if ( bounds.getStatus( i ) == ST_INACTIVE ) /* inactive? */
|
||
|
BC_status = ST_LOWER;
|
||
|
else
|
||
|
BC_status = ST_INACTIVE;
|
||
|
}
|
||
|
|
||
|
/* 2) Consider upper blocking bounds. */
|
||
|
if ( maxStepLength[nV+nC+i] < tau_new )
|
||
|
{
|
||
|
tau_new = maxStepLength[nV+nC+i];
|
||
|
BC_idx = i;
|
||
|
BC_isBound = BT_TRUE;
|
||
|
BC_status = ST_UPPER;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for ( i=nV; i<nV+nC; ++i )
|
||
|
{
|
||
|
/* 3) Consider lower/dual blocking constraints. */
|
||
|
if ( maxStepLength[i] < tau_new )
|
||
|
{
|
||
|
tau_new = maxStepLength[i];
|
||
|
BC_idx = i-nV;
|
||
|
BC_isBound = BT_FALSE;
|
||
|
if ( constraints.getStatus( i-nV ) == ST_INACTIVE ) /* inactive? */
|
||
|
BC_status = ST_LOWER;
|
||
|
else
|
||
|
BC_status = ST_INACTIVE;
|
||
|
}
|
||
|
|
||
|
/* 4) Consider upper blocking constraints. */
|
||
|
if ( maxStepLength[nV+nC+i] < tau_new )
|
||
|
{
|
||
|
tau_new = maxStepLength[nV+nC+i];
|
||
|
BC_idx = i-nV;
|
||
|
BC_isBound = BT_FALSE;
|
||
|
BC_status = ST_UPPER;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* IV) CLEAR CYCLING DATA
|
||
|
* if a positive step can be taken */
|
||
|
if ( tau_new > 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; i<nFR; ++i )
|
||
|
{
|
||
|
ii = FR_idx[i];
|
||
|
x[ii] += tau*delta_xFR[i];
|
||
|
}
|
||
|
|
||
|
for( i=0; i<nFX; ++i )
|
||
|
{
|
||
|
ii = FX_idx[i];
|
||
|
x[ii] += tau*delta_xFX[i];
|
||
|
y[ii] += tau*delta_yFX[i];
|
||
|
}
|
||
|
|
||
|
for( i=0; i<nAC; ++i )
|
||
|
{
|
||
|
ii = AC_idx[i];
|
||
|
y[nV+ii] += tau*delta_yAC[i];
|
||
|
}
|
||
|
|
||
|
/* ... also for Ax. */
|
||
|
for( i=0; i<nIAC; ++i )
|
||
|
{
|
||
|
ii = IAC_idx[i];
|
||
|
if ( constraints.getType( ii ) != ST_UNBOUNDED )
|
||
|
Ax[ii] += tau*delta_Ax[ii];
|
||
|
}
|
||
|
for( i=0; i<nAC; ++i )
|
||
|
{
|
||
|
ii = AC_idx[i];
|
||
|
|
||
|
Ax[ii] = 0.0;
|
||
|
for( j=0; j<nV; ++j )
|
||
|
Ax[ii] += A[ii*NVMAX + j] * x[j];
|
||
|
}
|
||
|
|
||
|
/* 2) Shift QP data. */
|
||
|
for( i=0; i<nV; ++i )
|
||
|
{
|
||
|
g[i] += tau*delta_g[i];
|
||
|
lb[i] += tau*delta_lb[i];
|
||
|
ub[i] += tau*delta_ub[i];
|
||
|
}
|
||
|
|
||
|
for( i=0; i<nC; ++i )
|
||
|
{
|
||
|
lbA[i] += tau*delta_lbA[i];
|
||
|
ubA[i] += tau*delta_ubA[i];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* print a stepsize warning if stepsize is zero */
|
||
|
#ifdef PC_DEBUG
|
||
|
char messageString[80];
|
||
|
sprintf( messageString,"Stepsize is %.6e",tau );
|
||
|
getGlobalMessageHandler( )->throwWarning( 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<getNC( ); ++i )
|
||
|
if ( ( lbA[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; i<nC; ++i )
|
||
|
for( j=0; j<nV; ++j )
|
||
|
A[i*NVMAX + j] = _A[i*nV + j];
|
||
|
|
||
|
/* 3) Setup lower constraints' bounds vector. */
|
||
|
if ( _lbA != 0 )
|
||
|
{
|
||
|
for( i=0; i<nC; ++i )
|
||
|
lbA[i] = _lbA[i];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* if no lower constraints' bounds are specified, set them to -infinity */
|
||
|
for( i=0; i<nC; ++i )
|
||
|
lbA[i] = -INFTY;
|
||
|
}
|
||
|
|
||
|
/* 4) Setup upper constraints' bounds vector. */
|
||
|
if ( _ubA != 0 )
|
||
|
{
|
||
|
for( i=0; i<nC; ++i )
|
||
|
ubA[i] = _ubA[i];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* if no upper constraints' bounds are specified, set them to infinity */
|
||
|
for( i=0; i<nC; ++i )
|
||
|
ubA[i] = INFTY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// printmatrix2( "A",A,10,20 );
|
||
|
|
||
|
// printmatrix2( "lbA",lbA,1,nC );
|
||
|
// printmatrix2( "ubA",ubA,1,nC );
|
||
|
|
||
|
return SUCCESSFUL_RETURN;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
#ifdef PC_DEBUG /* Define print functions only for debugging! */
|
||
|
|
||
|
/*
|
||
|
* p r i n t I t e r a t i o n
|
||
|
*/
|
||
|
returnValue QProblem::printIteration( int iteration,
|
||
|
int BC_idx, SubjectToStatus BC_status, BooleanType BC_isBound
|
||
|
)
|
||
|
{
|
||
|
char myPrintfString[160];
|
||
|
|
||
|
/* consistency check */
|
||
|
if ( iteration < 0 )
|
||
|
return THROWERROR( RET_INVALID_ARGUMENTS );
|
||
|
|
||
|
/* nothing to do */
|
||
|
if ( printlevel != PL_MEDIUM )
|
||
|
return SUCCESSFUL_RETURN;
|
||
|
|
||
|
|
||
|
/* 1) Print header at first iteration. */
|
||
|
if ( iteration == 0 )
|
||
|
{
|
||
|
sprintf( myPrintfString,"\n############## qpOASES -- QP NO.%4.1d ###############\n", count );
|
||
|
myPrintf( myPrintfString );
|
||
|
|
||
|
sprintf( myPrintfString," Iter | StepLength | Info | nFX | nAC \n" );
|
||
|
myPrintf( myPrintfString );
|
||
|
}
|
||
|
|
||
|
/* 2) Print iteration line. */
|
||
|
if ( BC_status == ST_UNDEFINED )
|
||
|
{
|
||
|
sprintf( myPrintfString," %4.1d | %1.5e | QP SOLVED | %4.1d | %4.1d \n", iteration,tau,getNFX( ),getNAC( ) );
|
||
|
myPrintf( myPrintfString );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
char info[8];
|
||
|
|
||
|
if ( BC_status == ST_INACTIVE )
|
||
|
sprintf( info,"REM " );
|
||
|
else
|
||
|
sprintf( info,"ADD " );
|
||
|
|
||
|
if ( BC_isBound == BT_TRUE )
|
||
|
sprintf( &(info[4]),"BND" );
|
||
|
else
|
||
|
sprintf( &(info[4]),"CON" );
|
||
|
|
||
|
sprintf( myPrintfString," %4.1d | %1.5e | %s%4.1d | %4.1d | %4.1d \n", iteration,tau,info,BC_idx,getNFX( ),getNAC( ) );
|
||
|
myPrintf( myPrintfString );
|
||
|
}
|
||
|
|
||
|
return SUCCESSFUL_RETURN;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* p r i n t I t e r a t i o n
|
||
|
*/
|
||
|
returnValue QProblem::printIteration( int iteration,
|
||
|
int BC_idx, SubjectToStatus BC_status
|
||
|
)
|
||
|
{
|
||
|
return printIteration( iteration,BC_idx,BC_status,BT_TRUE );
|
||
|
}
|
||
|
|
||
|
#endif /* PC_DEBUG */
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* c h e c k K K T c o n d i t i o n s
|
||
|
*/
|
||
|
returnValue QProblem::checkKKTconditions( )
|
||
|
{
|
||
|
#ifdef __PERFORM_KKT_TEST__
|
||
|
|
||
|
int i, j, jj;
|
||
|
int nV = getNV( );
|
||
|
int nC = getNC( );
|
||
|
int nAC = getNAC( );
|
||
|
|
||
|
real_t tmp;
|
||
|
real_t maxKKTviolation = 0.0;
|
||
|
|
||
|
int AC_idx[NCMAX_ALLOC];
|
||
|
constraints.getActive( )->getNumberArray( AC_idx );
|
||
|
|
||
|
/* 1) check for Hx + g - [yFX yAC]*[Id A]' = 0. */
|
||
|
for( i=0; i<nV; ++i )
|
||
|
{
|
||
|
tmp = g[i];
|
||
|
|
||
|
for( j=0; j<nV; ++j )
|
||
|
tmp += H[i*NVMAX + j] * x[j];
|
||
|
|
||
|
tmp -= y[i];
|
||
|
|
||
|
/* Only sum over active constraints as y is zero for all inactive ones. */
|
||
|
for( j=0; j<nAC; ++j )
|
||
|
{
|
||
|
jj = AC_idx[j];
|
||
|
tmp -= A[jj*NVMAX + i] * y[nV+jj];
|
||
|
}
|
||
|
|
||
|
if ( getAbs( tmp ) > maxKKTviolation )
|
||
|
maxKKTviolation = getAbs( tmp );
|
||
|
}
|
||
|
|
||
|
/* 2) Check for [lb lbA] <= [Id A]*x <= [ub ubA]. */
|
||
|
/* lbA <= Ax <= ubA */
|
||
|
for( i=0; i<nC; ++i )
|
||
|
{
|
||
|
if ( lbA[i] - Ax[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<nV; ++i )
|
||
|
{
|
||
|
if ( lb[i] - x[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<nV; ++i )
|
||
|
{
|
||
|
switch ( bounds.getStatus( i ) )
|
||
|
{
|
||
|
case ST_LOWER:
|
||
|
if ( -y[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<nC; ++i )
|
||
|
{
|
||
|
switch ( constraints.getStatus( i ) )
|
||
|
{
|
||
|
case ST_LOWER:
|
||
|
if ( -y[nV+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
|
||
|
*/
|