2017-08-01 12:30:58 +00:00
/* Copyright (C) 2004-2013 MBSim Development Team
Code was converted for the Bullet Continuous Collision Detection and Physics Library
This software is provided ' as - is ' , without any express or implied warranty .
In no event will the authors be held liable for any damages arising from the use of this software .
Permission is granted to anyone to use this software for any purpose ,
including commercial applications , and to alter it and redistribute it freely ,
subject to the following restrictions :
1. The origin of this software must not be misrepresented ; you must not claim that you wrote the original software . If you use this software in a product , an acknowledgment in the product documentation would be appreciated but is not required .
2. Altered source versions must be plainly marked as such , and must not be misrepresented as being the original software .
3. This notice may not be removed or altered from any source distribution .
*/
//The original version is here
//https://code.google.com/p/mbsim-env/source/browse/trunk/kernel/mbsim/numerics/linear_complementarity_problem/lemke_algorithm.cc
//This file is re-distributed under the ZLib license, with permission of the original author
//Math library was replaced from fmatvec to a the file src/LinearMath/btMatrixX.h
//STL/std::vector replaced by btAlignedObjectArray
# include "btLemkeAlgorithm.h"
# undef BT_DEBUG_OSTREAM
# ifdef BT_DEBUG_OSTREAM
using namespace std ;
2019-01-03 13:26:51 +00:00
# endif //BT_DEBUG_OSTREAM
2017-08-01 12:30:58 +00:00
btScalar btMachEps ( )
{
2019-01-03 13:26:51 +00:00
static bool calculated = false ;
2017-08-01 12:30:58 +00:00
static btScalar machEps = btScalar ( 1. ) ;
if ( ! calculated )
{
2019-01-03 13:26:51 +00:00
do
{
2017-08-01 12:30:58 +00:00
machEps / = btScalar ( 2.0 ) ;
// If next epsilon yields 1, then break, because current
// epsilon is the machine epsilon.
2019-01-03 13:26:51 +00:00
} while ( ( btScalar ) ( 1.0 + ( machEps / btScalar ( 2.0 ) ) ) ! = btScalar ( 1.0 ) ) ;
// printf( "\nCalculated Machine epsilon: %G\n", machEps );
calculated = true ;
2017-08-01 12:30:58 +00:00
}
return machEps ;
}
2019-01-03 13:26:51 +00:00
btScalar btEpsRoot ( )
{
2017-08-01 12:30:58 +00:00
static btScalar epsroot = 0. ;
static bool alreadyCalculated = false ;
2019-01-03 13:26:51 +00:00
if ( ! alreadyCalculated )
{
2017-08-01 12:30:58 +00:00
epsroot = btSqrt ( btMachEps ( ) ) ;
alreadyCalculated = true ;
}
return epsroot ;
}
2019-01-03 13:26:51 +00:00
btVectorXu btLemkeAlgorithm : : solve ( unsigned int maxloops /* = 0*/ )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
steps = 0 ;
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
int dim = m_q . size ( ) ;
2017-08-01 12:30:58 +00:00
# ifdef BT_DEBUG_OSTREAM
2019-01-03 13:26:51 +00:00
if ( DEBUGLEVEL > = 1 )
{
cout < < " Dimension = " < < dim < < endl ;
}
# endif //BT_DEBUG_OSTREAM
2017-08-01 12:30:58 +00:00
btVectorXu solutionVector ( 2 * dim ) ;
solutionVector . setZero ( ) ;
2019-01-03 13:26:51 +00:00
//, INIT, 0.);
2017-08-01 12:30:58 +00:00
btMatrixXu ident ( dim , dim ) ;
ident . setIdentity ( ) ;
# ifdef BT_DEBUG_OSTREAM
cout < < m_M < < std : : endl ;
# endif
btMatrixXu mNeg = m_M . negative ( ) ;
2019-01-03 13:26:51 +00:00
btMatrixXu A ( dim , 2 * dim + 2 ) ;
2017-08-01 12:30:58 +00:00
//
2019-01-03 13:26:51 +00:00
A . setSubMatrix ( 0 , 0 , dim - 1 , dim - 1 , ident ) ;
A . setSubMatrix ( 0 , dim , dim - 1 , 2 * dim - 1 , mNeg ) ;
2017-08-01 12:30:58 +00:00
A . setSubMatrix ( 0 , 2 * dim , dim - 1 , 2 * dim , - 1.f ) ;
2019-01-03 13:26:51 +00:00
A . setSubMatrix ( 0 , 2 * dim + 1 , dim - 1 , 2 * dim + 1 , m_q ) ;
2017-08-01 12:30:58 +00:00
# ifdef BT_DEBUG_OSTREAM
cout < < A < < std : : endl ;
2019-01-03 13:26:51 +00:00
# endif //BT_DEBUG_OSTREAM
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
// btVectorXu q_;
// q_ >> A(0, 2 * dim + 1, dim - 1, 2 * dim + 1);
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
btAlignedObjectArray < int > basis ;
//At first, all w-values are in the basis
for ( int i = 0 ; i < dim ; i + + )
basis . push_back ( i ) ;
2017-08-01 12:30:58 +00:00
int pivotRowIndex = - 1 ;
btScalar minValue = 1e30 f ;
bool greaterZero = true ;
2019-01-03 13:26:51 +00:00
for ( int i = 0 ; i < dim ; i + + )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
btScalar v = A ( i , 2 * dim + 1 ) ;
if ( v < minValue )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
minValue = v ;
2017-08-01 12:30:58 +00:00
pivotRowIndex = i ;
}
2019-01-03 13:26:51 +00:00
if ( v < 0 )
2017-08-01 12:30:58 +00:00
greaterZero = false ;
}
2019-01-03 13:26:51 +00:00
// int pivotRowIndex = q_.minIndex();//minIndex(q_); // first row is that with lowest q-value
int z0Row = pivotRowIndex ; // remember the col of z0 for ending algorithm afterwards
int pivotColIndex = 2 * dim ; // first col is that of z0
2017-08-01 12:30:58 +00:00
# ifdef BT_DEBUG_OSTREAM
2019-01-03 13:26:51 +00:00
if ( DEBUGLEVEL > = 3 )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
// cout << "A: " << A << endl;
cout < < " pivotRowIndex " < < pivotRowIndex < < endl ;
cout < < " pivotColIndex " < < pivotColIndex < < endl ;
cout < < " Basis: " ;
for ( int i = 0 ; i < basis . size ( ) ; i + + )
cout < < basis [ i ] < < " " ;
cout < < endl ;
}
# endif //BT_DEBUG_OSTREAM
2017-08-01 12:30:58 +00:00
if ( ! greaterZero )
{
2019-01-03 13:26:51 +00:00
if ( maxloops = = 0 )
{
maxloops = 100 ;
// maxloops = UINT_MAX; //TODO: not a really nice way, problem is: maxloops should be 2^dim (=1<<dim), but this could exceed UINT_MAX and thus the result would be 0 and therefore the lemke algorithm wouldn't start but probably would find a solution within less then UINT_MAX steps. Therefore this constant is used as a upper border right now...
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
/*start looping*/
for ( steps = 0 ; steps < maxloops ; steps + + )
{
GaussJordanEliminationStep ( A , pivotRowIndex , pivotColIndex , basis ) ;
2017-08-01 12:30:58 +00:00
# ifdef BT_DEBUG_OSTREAM
2019-01-03 13:26:51 +00:00
if ( DEBUGLEVEL > = 3 )
{
// cout << "A: " << A << endl;
cout < < " pivotRowIndex " < < pivotRowIndex < < endl ;
cout < < " pivotColIndex " < < pivotColIndex < < endl ;
cout < < " Basis: " ;
for ( int i = 0 ; i < basis . size ( ) ; i + + )
cout < < basis [ i ] < < " " ;
cout < < endl ;
}
# endif //BT_DEBUG_OSTREAM
int pivotColIndexOld = pivotColIndex ;
/*find new column index */
if ( basis [ pivotRowIndex ] < dim ) //if a w-value left the basis get in the correspondent z-value
pivotColIndex = basis [ pivotRowIndex ] + dim ;
else
//else do it the other way round and get in the corresponding w-value
pivotColIndex = basis [ pivotRowIndex ] - dim ;
/*the column becomes part of the basis*/
basis [ pivotRowIndex ] = pivotColIndexOld ;
pivotRowIndex = findLexicographicMinimum ( A , pivotColIndex ) ;
if ( z0Row = = pivotRowIndex )
{ //if z0 leaves the basis the solution is found --> one last elimination step is necessary
GaussJordanEliminationStep ( A , pivotRowIndex , pivotColIndex , basis ) ;
basis [ pivotRowIndex ] = pivotColIndex ; //update basis
break ;
}
}
2017-08-01 12:30:58 +00:00
# ifdef BT_DEBUG_OSTREAM
2019-01-03 13:26:51 +00:00
if ( DEBUGLEVEL > = 1 )
{
cout < < " Number of loops: " < < steps < < endl ;
cout < < " Number of maximal loops: " < < maxloops < < endl ;
}
# endif //BT_DEBUG_OSTREAM
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
if ( ! validBasis ( basis ) )
{
info = - 1 ;
# ifdef BT_DEBUG_OSTREAM
if ( DEBUGLEVEL > = 1 )
cerr < < " Lemke-Algorithm ended with Ray-Termination (no valid solution). " < < endl ;
# endif //BT_DEBUG_OSTREAM
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
return solutionVector ;
}
}
2017-08-01 12:30:58 +00:00
# ifdef BT_DEBUG_OSTREAM
2019-01-03 13:26:51 +00:00
if ( DEBUGLEVEL > = 2 )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
// cout << "A: " << A << endl;
cout < < " pivotRowIndex " < < pivotRowIndex < < endl ;
cout < < " pivotColIndex " < < pivotColIndex < < endl ;
2017-08-01 12:30:58 +00:00
}
2019-01-03 13:26:51 +00:00
# endif //BT_DEBUG_OSTREAM
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
for ( int i = 0 ; i < basis . size ( ) ; i + + )
{
solutionVector [ basis [ i ] ] = A ( i , 2 * dim + 1 ) ; //q_[i];
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
info = 0 ;
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
return solutionVector ;
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
int btLemkeAlgorithm : : findLexicographicMinimum ( const btMatrixXu & A , const int & pivotColIndex )
{
int RowIndex = 0 ;
int dim = A . rows ( ) ;
btAlignedObjectArray < btVectorXu > Rows ;
for ( int row = 0 ; row < dim ; row + + )
{
btVectorXu vec ( dim + 1 ) ;
vec . setZero ( ) ; //, INIT, 0.)
Rows . push_back ( vec ) ;
btScalar a = A ( row , pivotColIndex ) ;
if ( a > 0 )
{
Rows [ row ] [ 0 ] = A ( row , 2 * dim + 1 ) / a ;
Rows [ row ] [ 1 ] = A ( row , 2 * dim ) / a ;
for ( int j = 2 ; j < dim + 1 ; j + + )
Rows [ row ] [ j ] = A ( row , j - 1 ) / a ;
2017-08-01 12:30:58 +00:00
# ifdef BT_DEBUG_OSTREAM
2019-01-03 13:26:51 +00:00
// if (DEBUGLEVEL) {
// cout << "Rows(" << row << ") = " << Rows[row] << endl;
2017-08-01 12:30:58 +00:00
// }
2019-01-03 13:26:51 +00:00
# endif
}
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
for ( int i = 0 ; i < Rows . size ( ) ; i + + )
{
if ( Rows [ i ] . nrm2 ( ) > 0. )
{
int j = 0 ;
for ( ; j < Rows . size ( ) ; j + + )
{
if ( i ! = j )
{
if ( Rows [ j ] . nrm2 ( ) > 0. )
{
btVectorXu test ( dim + 1 ) ;
for ( int ii = 0 ; ii < dim + 1 ; ii + + )
{
test [ ii ] = Rows [ j ] [ ii ] - Rows [ i ] [ ii ] ;
}
//=Rows[j] - Rows[i]
if ( ! LexicographicPositive ( test ) )
break ;
}
}
}
if ( j = = Rows . size ( ) )
{
RowIndex + = i ;
break ;
}
}
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
return RowIndex ;
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
bool btLemkeAlgorithm : : LexicographicPositive ( const btVectorXu & v )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
int i = 0 ;
// if (DEBUGLEVEL)
// cout << "v " << v << endl;
while ( i < v . size ( ) - 1 & & fabs ( v [ i ] ) < btMachEps ( ) )
i + + ;
if ( v [ i ] > 0 )
return true ;
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
return false ;
}
void btLemkeAlgorithm : : GaussJordanEliminationStep ( btMatrixXu & A , int pivotRowIndex , int pivotColumnIndex , const btAlignedObjectArray < int > & basis )
{
2017-08-01 12:30:58 +00:00
btScalar a = - 1 / A ( pivotRowIndex , pivotColumnIndex ) ;
# ifdef BT_DEBUG_OSTREAM
cout < < A < < std : : endl ;
# endif
2019-01-03 13:26:51 +00:00
for ( int i = 0 ; i < A . rows ( ) ; i + + )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
if ( i ! = pivotRowIndex )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
for ( int j = 0 ; j < A . cols ( ) ; j + + )
{
if ( j ! = pivotColumnIndex )
{
btScalar v = A ( i , j ) ;
v + = A ( pivotRowIndex , j ) * A ( i , pivotColumnIndex ) * a ;
A . setElem ( i , j , v ) ;
}
}
2017-08-01 12:30:58 +00:00
}
}
# ifdef BT_DEBUG_OSTREAM
cout < < A < < std : : endl ;
2019-01-03 13:26:51 +00:00
# endif //BT_DEBUG_OSTREAM
for ( int i = 0 ; i < A . cols ( ) ; i + + )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
A . mulElem ( pivotRowIndex , i , - a ) ;
}
2017-08-01 12:30:58 +00:00
# ifdef BT_DEBUG_OSTREAM
cout < < A < < std : : endl ;
2019-01-03 13:26:51 +00:00
# endif //#ifdef BT_DEBUG_OSTREAM
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
for ( int i = 0 ; i < A . rows ( ) ; i + + )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
if ( i ! = pivotRowIndex )
{
A . setElem ( i , pivotColumnIndex , 0 ) ;
}
2017-08-01 12:30:58 +00:00
}
# ifdef BT_DEBUG_OSTREAM
cout < < A < < std : : endl ;
2019-01-03 13:26:51 +00:00
# endif //#ifdef BT_DEBUG_OSTREAM
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
bool btLemkeAlgorithm : : greaterZero ( const btVectorXu & vector )
2017-08-01 12:30:58 +00:00
{
2019-01-03 13:26:51 +00:00
bool isGreater = true ;
for ( int i = 0 ; i < vector . size ( ) ; i + + )
{
if ( vector [ i ] < 0 )
{
isGreater = false ;
break ;
}
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
return isGreater ;
}
2017-08-01 12:30:58 +00:00
2019-01-03 13:26:51 +00:00
bool btLemkeAlgorithm : : validBasis ( const btAlignedObjectArray < int > & basis )
{
bool isValid = true ;
for ( int i = 0 ; i < basis . size ( ) ; i + + )
{
if ( basis [ i ] > = basis . size ( ) * 2 )
{ //then z0 is in the base
isValid = false ;
break ;
}
}
return isValid ;
}