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
22 #include "btLemkeAlgorithm.h"
24 #undef BT_DEBUG_OSTREAM
25 #ifdef BT_DEBUG_OSTREAM
27 #endif //BT_DEBUG_OSTREAM
31 static bool calculated = false;
32 static btScalar machEps = btScalar(1.);
37 machEps /= btScalar(2.0);
38 // If next epsilon yields 1, then break, because current
39 // epsilon is the machine epsilon.
40 } while ((btScalar)(1.0 + (machEps / btScalar(2.0))) != btScalar(1.0));
41 // printf( "\nCalculated Machine epsilon: %G\n", machEps );
49 static btScalar epsroot = 0.;
50 static bool alreadyCalculated = false;
52 if (!alreadyCalculated)
54 epsroot = btSqrt(btMachEps());
55 alreadyCalculated = true;
60 btVectorXu btLemkeAlgorithm::solve(unsigned int maxloops /* = 0*/)
65 #ifdef BT_DEBUG_OSTREAM
68 cout << "Dimension = " << dim << endl;
70 #endif //BT_DEBUG_OSTREAM
72 btVectorXu solutionVector(2 * dim);
73 solutionVector.setZero();
77 btMatrixXu ident(dim, dim);
79 #ifdef BT_DEBUG_OSTREAM
80 cout << m_M << std::endl;
83 btMatrixXu mNeg = m_M.negative();
85 btMatrixXu A(dim, 2 * dim + 2);
87 A.setSubMatrix(0, 0, dim - 1, dim - 1, ident);
88 A.setSubMatrix(0, dim, dim - 1, 2 * dim - 1, mNeg);
89 A.setSubMatrix(0, 2 * dim, dim - 1, 2 * dim, -1.f);
90 A.setSubMatrix(0, 2 * dim + 1, dim - 1, 2 * dim + 1, m_q);
92 #ifdef BT_DEBUG_OSTREAM
93 cout << A << std::endl;
94 #endif //BT_DEBUG_OSTREAM
97 // q_ >> A(0, 2 * dim + 1, dim - 1, 2 * dim + 1);
99 btAlignedObjectArray<int> basis;
100 //At first, all w-values are in the basis
101 for (int i = 0; i < dim; i++)
104 int pivotRowIndex = -1;
105 btScalar minValue = 1e30f;
106 bool greaterZero = true;
107 for (int i = 0; i < dim; i++)
109 btScalar v = A(i, 2 * dim + 1);
119 // int pivotRowIndex = q_.minIndex();//minIndex(q_); // first row is that with lowest q-value
120 int z0Row = pivotRowIndex; // remember the col of z0 for ending algorithm afterwards
121 int pivotColIndex = 2 * dim; // first col is that of z0
123 #ifdef BT_DEBUG_OSTREAM
126 // cout << "A: " << A << endl;
127 cout << "pivotRowIndex " << pivotRowIndex << endl;
128 cout << "pivotColIndex " << pivotColIndex << endl;
130 for (int i = 0; i < basis.size(); i++)
131 cout << basis[i] << " ";
134 #endif //BT_DEBUG_OSTREAM
141 // 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...
145 for (steps = 0; steps < maxloops; steps++)
147 GaussJordanEliminationStep(A, pivotRowIndex, pivotColIndex, basis);
148 #ifdef BT_DEBUG_OSTREAM
151 // cout << "A: " << A << endl;
152 cout << "pivotRowIndex " << pivotRowIndex << endl;
153 cout << "pivotColIndex " << pivotColIndex << endl;
155 for (int i = 0; i < basis.size(); i++)
156 cout << basis[i] << " ";
159 #endif //BT_DEBUG_OSTREAM
161 int pivotColIndexOld = pivotColIndex;
163 /*find new column index */
164 if (basis[pivotRowIndex] < dim) //if a w-value left the basis get in the correspondent z-value
165 pivotColIndex = basis[pivotRowIndex] + dim;
167 //else do it the other way round and get in the corresponding w-value
168 pivotColIndex = basis[pivotRowIndex] - dim;
170 /*the column becomes part of the basis*/
171 basis[pivotRowIndex] = pivotColIndexOld;
172 bool isRayTermination = false;
173 pivotRowIndex = findLexicographicMinimum(A, pivotColIndex, z0Row, isRayTermination);
174 if (isRayTermination)
176 break; // ray termination
178 if (z0Row == pivotRowIndex)
179 { //if z0 leaves the basis the solution is found --> one last elimination step is necessary
180 GaussJordanEliminationStep(A, pivotRowIndex, pivotColIndex, basis);
181 basis[pivotRowIndex] = pivotColIndex; //update basis
185 #ifdef BT_DEBUG_OSTREAM
188 cout << "Number of loops: " << steps << endl;
189 cout << "Number of maximal loops: " << maxloops << endl;
191 #endif //BT_DEBUG_OSTREAM
193 if (!validBasis(basis))
196 #ifdef BT_DEBUG_OSTREAM
198 cerr << "Lemke-Algorithm ended with Ray-Termination (no valid solution)." << endl;
199 #endif //BT_DEBUG_OSTREAM
201 return solutionVector;
204 #ifdef BT_DEBUG_OSTREAM
207 // cout << "A: " << A << endl;
208 cout << "pivotRowIndex " << pivotRowIndex << endl;
209 cout << "pivotColIndex " << pivotColIndex << endl;
211 #endif //BT_DEBUG_OSTREAM
213 for (int i = 0; i < basis.size(); i++)
215 solutionVector[basis[i]] = A(i, 2 * dim + 1); //q_[i];
220 return solutionVector;
223 int btLemkeAlgorithm::findLexicographicMinimum(const btMatrixXu& A, const int& pivotColIndex, const int& z0Row, bool& isRayTermination)
225 isRayTermination = false;
226 btAlignedObjectArray<int> activeRows;
228 bool firstRow = true;
229 btScalar currentMin = 0.0;
233 for (int row = 0; row < dim; row++)
235 const btScalar denom = A(row, pivotColIndex);
237 if (denom > btMachEps())
239 const btScalar q = A(row, dim + dim + 1) / denom;
243 activeRows.push_back(row);
246 else if (fabs(currentMin - q) < btMachEps())
248 activeRows.push_back(row);
250 else if (currentMin > q)
254 activeRows.push_back(row);
259 if (activeRows.size() == 0)
261 isRayTermination = true;
264 else if (activeRows.size() == 1)
266 return activeRows[0];
269 // if there are multiple rows, check if they contain the row for z_0.
270 for (int i = 0; i < activeRows.size(); i++)
272 if (activeRows[i] == z0Row)
278 // look through the columns of the inverse of the basic matrix from left to right until the tie is broken.
279 for (int col = 0; col < dim ; col++)
281 btAlignedObjectArray<int> activeRowsCopy(activeRows);
284 for (int i = 0; i<activeRowsCopy.size();i++)
286 const int row = activeRowsCopy[i];
288 // denom is positive here as an invariant.
289 const btScalar denom = A(row, pivotColIndex);
290 const btScalar ratio = A(row, col) / denom;
294 activeRows.push_back(row);
297 else if (fabs(currentMin - ratio) < btMachEps())
299 activeRows.push_back(row);
301 else if (currentMin > ratio)
305 activeRows.push_back(row);
309 if (activeRows.size() == 1)
311 return activeRows[0];
314 // must not reach here.
315 isRayTermination = true;
319 void btLemkeAlgorithm::GaussJordanEliminationStep(btMatrixXu& A, int pivotRowIndex, int pivotColumnIndex, const btAlignedObjectArray<int>& basis)
321 btScalar a = -1 / A(pivotRowIndex, pivotColumnIndex);
322 #ifdef BT_DEBUG_OSTREAM
323 cout << A << std::endl;
326 for (int i = 0; i < A.rows(); i++)
328 if (i != pivotRowIndex)
330 for (int j = 0; j < A.cols(); j++)
332 if (j != pivotColumnIndex)
334 btScalar v = A(i, j);
335 v += A(pivotRowIndex, j) * A(i, pivotColumnIndex) * a;
342 #ifdef BT_DEBUG_OSTREAM
343 cout << A << std::endl;
344 #endif //BT_DEBUG_OSTREAM
345 for (int i = 0; i < A.cols(); i++)
347 A.mulElem(pivotRowIndex, i, -a);
349 #ifdef BT_DEBUG_OSTREAM
350 cout << A << std::endl;
351 #endif //#ifdef BT_DEBUG_OSTREAM
353 for (int i = 0; i < A.rows(); i++)
355 if (i != pivotRowIndex)
357 A.setElem(i, pivotColumnIndex, 0);
360 #ifdef BT_DEBUG_OSTREAM
361 cout << A << std::endl;
362 #endif //#ifdef BT_DEBUG_OSTREAM
365 bool btLemkeAlgorithm::greaterZero(const btVectorXu& vector)
367 bool isGreater = true;
368 for (int i = 0; i < vector.size(); i++)
380 bool btLemkeAlgorithm::validBasis(const btAlignedObjectArray<int>& basis)
383 for (int i = 0; i < basis.size(); i++)
385 if (basis[i] >= basis.size() * 2)
386 { //then z0 is in the base