1 /* Copyright (C) 2004-2013 MBSim Development Team
3 Code was converted for the Bullet Continuous Collision Detection and Physics Library
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
11 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.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
16 //The original version is here
17 //https://code.google.com/p/mbsim-env/source/browse/trunk/kernel/mbsim/numerics/linear_complementarity_problem/lemke_algorithm.cc
18 //This file is re-distributed under the ZLib license, with permission of the original author
19 //Math library was replaced from fmatvec to a the file src/LinearMath/btMatrixX.h
20 //STL/std::vector replaced by btAlignedObjectArray
24 #include "btLemkeAlgorithm.h"
26 #undef BT_DEBUG_OSTREAM
27 #ifdef BT_DEBUG_OSTREAM
29 #endif //BT_DEBUG_OSTREAM
33 static bool calculated
=false;
34 static btScalar machEps
= btScalar(1.);
38 machEps
/= btScalar(2.0);
39 // If next epsilon yields 1, then break, because current
40 // epsilon is the machine epsilon.
42 while ((btScalar
)(1.0 + (machEps
/btScalar(2.0))) != btScalar(1.0));
43 // printf( "\nCalculated Machine epsilon: %G\n", machEps );
49 btScalar
btEpsRoot() {
51 static btScalar epsroot
= 0.;
52 static bool alreadyCalculated
= false;
54 if (!alreadyCalculated
) {
55 epsroot
= btSqrt(btMachEps());
56 alreadyCalculated
= true;
63 btVectorXu
btLemkeAlgorithm::solve(unsigned int maxloops
/* = 0*/)
70 #ifdef BT_DEBUG_OSTREAM
72 cout
<< "Dimension = " << dim
<< endl
;
74 #endif //BT_DEBUG_OSTREAM
76 btVectorXu
solutionVector(2 * dim
);
77 solutionVector
.setZero();
81 btMatrixXu
ident(dim
, dim
);
83 #ifdef BT_DEBUG_OSTREAM
84 cout
<< m_M
<< std::endl
;
87 btMatrixXu mNeg
= m_M
.negative();
89 btMatrixXu
A(dim
, 2 * dim
+ 2);
91 A
.setSubMatrix(0, 0, dim
- 1, dim
- 1,ident
);
92 A
.setSubMatrix(0, dim
, dim
- 1, 2 * dim
- 1,mNeg
);
93 A
.setSubMatrix(0, 2 * dim
, dim
- 1, 2 * dim
, -1.f
);
94 A
.setSubMatrix(0, 2 * dim
+ 1, dim
- 1, 2 * dim
+ 1,m_q
);
96 #ifdef BT_DEBUG_OSTREAM
97 cout
<< A
<< std::endl
;
98 #endif //BT_DEBUG_OSTREAM
102 // q_ >> A(0, 2 * dim + 1, dim - 1, 2 * dim + 1);
104 btAlignedObjectArray
<int> basis
;
105 //At first, all w-values are in the basis
106 for (int i
= 0; i
< dim
; i
++)
109 int pivotRowIndex
= -1;
110 btScalar minValue
= 1e30f
;
111 bool greaterZero
= true;
112 for (int i
=0;i
<dim
;i
++)
114 btScalar v
=A(i
,2*dim
+1);
126 // int pivotRowIndex = q_.minIndex();//minIndex(q_); // first row is that with lowest q-value
127 int z0Row
= pivotRowIndex
; // remember the col of z0 for ending algorithm afterwards
128 int pivotColIndex
= 2 * dim
; // first col is that of z0
130 #ifdef BT_DEBUG_OSTREAM
133 // cout << "A: " << A << endl;
134 cout
<< "pivotRowIndex " << pivotRowIndex
<< endl
;
135 cout
<< "pivotColIndex " << pivotColIndex
<< endl
;
137 for (int i
= 0; i
< basis
.size(); i
++)
138 cout
<< basis
[i
] << " ";
141 #endif //BT_DEBUG_OSTREAM
148 // 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...
152 for(steps
= 0; steps
< maxloops
; steps
++) {
154 GaussJordanEliminationStep(A
, pivotRowIndex
, pivotColIndex
, basis
);
155 #ifdef BT_DEBUG_OSTREAM
156 if (DEBUGLEVEL
>= 3) {
157 // cout << "A: " << A << endl;
158 cout
<< "pivotRowIndex " << pivotRowIndex
<< endl
;
159 cout
<< "pivotColIndex " << pivotColIndex
<< endl
;
161 for (int i
= 0; i
< basis
.size(); i
++)
162 cout
<< basis
[i
] << " ";
165 #endif //BT_DEBUG_OSTREAM
167 int pivotColIndexOld
= pivotColIndex
;
169 /*find new column index */
170 if (basis
[pivotRowIndex
] < dim
) //if a w-value left the basis get in the correspondent z-value
171 pivotColIndex
= basis
[pivotRowIndex
] + dim
;
173 //else do it the other way round and get in the corresponding w-value
174 pivotColIndex
= basis
[pivotRowIndex
] - dim
;
176 /*the column becomes part of the basis*/
177 basis
[pivotRowIndex
] = pivotColIndexOld
;
179 pivotRowIndex
= findLexicographicMinimum(A
, pivotColIndex
);
181 if(z0Row
== pivotRowIndex
) { //if z0 leaves the basis the solution is found --> one last elimination step is necessary
182 GaussJordanEliminationStep(A
, pivotRowIndex
, pivotColIndex
, basis
);
183 basis
[pivotRowIndex
] = pivotColIndex
; //update basis
188 #ifdef BT_DEBUG_OSTREAM
189 if(DEBUGLEVEL
>= 1) {
190 cout
<< "Number of loops: " << steps
<< endl
;
191 cout
<< "Number of maximal loops: " << maxloops
<< endl
;
193 #endif //BT_DEBUG_OSTREAM
195 if(!validBasis(basis
)) {
197 #ifdef BT_DEBUG_OSTREAM
199 cerr
<< "Lemke-Algorithm ended with Ray-Termination (no valid solution)." << endl
;
200 #endif //BT_DEBUG_OSTREAM
202 return solutionVector
;
206 #ifdef BT_DEBUG_OSTREAM
207 if (DEBUGLEVEL
>= 2) {
208 // cout << "A: " << A << endl;
209 cout
<< "pivotRowIndex " << pivotRowIndex
<< endl
;
210 cout
<< "pivotColIndex " << pivotColIndex
<< endl
;
212 #endif //BT_DEBUG_OSTREAM
214 for (int i
= 0; i
< basis
.size(); i
++)
216 solutionVector
[basis
[i
]] = A(i
,2*dim
+1);//q_[i];
221 return solutionVector
;
224 int btLemkeAlgorithm::findLexicographicMinimum(const btMatrixXu
& A
, const int & pivotColIndex
) {
227 btAlignedObjectArray
<btVectorXu
> Rows
;
228 for (int row
= 0; row
< dim
; row
++)
231 btVectorXu
vec(dim
+ 1);
232 vec
.setZero();//, INIT, 0.)
234 btScalar a
= A(row
, pivotColIndex
);
236 Rows
[row
][0] = A(row
, 2 * dim
+ 1) / a
;
237 Rows
[row
][1] = A(row
, 2 * dim
) / a
;
238 for (int j
= 2; j
< dim
+ 1; j
++)
239 Rows
[row
][j
] = A(row
, j
- 1) / a
;
241 #ifdef BT_DEBUG_OSTREAM
243 // cout << "Rows(" << row << ") = " << Rows[row] << endl;
249 for (int i
= 0; i
< Rows
.size(); i
++)
251 if (Rows
[i
].nrm2() > 0.) {
254 for (; j
< Rows
.size(); j
++)
258 if(Rows
[j
].nrm2() > 0.)
260 btVectorXu
test(dim
+ 1);
261 for (int ii
=0;ii
<dim
+1;ii
++)
263 test
[ii
] = Rows
[j
][ii
] - Rows
[i
][ii
];
267 if (! LexicographicPositive(test
))
273 if (j
== Rows
.size())
284 bool btLemkeAlgorithm::LexicographicPositive(const btVectorXu
& v
)
288 // cout << "v " << v << endl;
290 while(i
< v
.size()-1 && fabs(v
[i
]) < btMachEps())
298 void btLemkeAlgorithm::GaussJordanEliminationStep(btMatrixXu
& A
, int pivotRowIndex
, int pivotColumnIndex
, const btAlignedObjectArray
<int>& basis
)
301 btScalar a
= -1 / A(pivotRowIndex
, pivotColumnIndex
);
302 #ifdef BT_DEBUG_OSTREAM
303 cout
<< A
<< std::endl
;
306 for (int i
= 0; i
< A
.rows(); i
++)
308 if (i
!= pivotRowIndex
)
310 for (int j
= 0; j
< A
.cols(); j
++)
312 if (j
!= pivotColumnIndex
)
314 btScalar v
= A(i
, j
);
315 v
+= A(pivotRowIndex
, j
) * A(i
, pivotColumnIndex
) * a
;
322 #ifdef BT_DEBUG_OSTREAM
323 cout
<< A
<< std::endl
;
324 #endif //BT_DEBUG_OSTREAM
325 for (int i
= 0; i
< A
.cols(); i
++)
327 A
.mulElem(pivotRowIndex
, i
,-a
);
329 #ifdef BT_DEBUG_OSTREAM
330 cout
<< A
<< std::endl
;
331 #endif //#ifdef BT_DEBUG_OSTREAM
333 for (int i
= 0; i
< A
.rows(); i
++)
335 if (i
!= pivotRowIndex
)
337 A
.setElem(i
, pivotColumnIndex
,0);
340 #ifdef BT_DEBUG_OSTREAM
341 cout
<< A
<< std::endl
;
342 #endif //#ifdef BT_DEBUG_OSTREAM
345 bool btLemkeAlgorithm::greaterZero(const btVectorXu
& vector
)
347 bool isGreater
= true;
348 for (int i
= 0; i
< vector
.size(); i
++) {
358 bool btLemkeAlgorithm::validBasis(const btAlignedObjectArray
<int>& basis
)
361 for (int i
= 0; i
< basis
.size(); i
++) {
362 if (basis
[i
] >= basis
.size() * 2) { //then z0 is in the base