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.
		
		
		
		
		
			
		
			
				
					
					
						
							3867 lines
						
					
					
						
							90 KiB
						
					
					
				
			
		
		
	
	
							3867 lines
						
					
					
						
							90 KiB
						
					
					
				| /*
 | |
|  *	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
 | |
|  */
 | |
| 
 |