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