1 /*
2 * Copyright (c) 2011-2021, The DART development contributors
3 * All rights reserved.
4 *
5 * The list of contributors can be found at:
6 * https://github.com/dartsim/dart/blob/master/LICENSE
7 *
8 * This file is provided under the following "BSD-style" License:
9 * Redistribution and use in source and binary forms, with or
10 * without modification, are permitted provided that the following
11 * conditions are met:
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include "dart/constraint/DantzigLCPSolver.hpp"
34
35 #ifndef NDEBUG
36 # include <iomanip>
37 # include <iostream>
38 #endif
39
40 #include "dart/external/odelcpsolver/lcp.h"
41
42 #include "dart/common/Console.hpp"
43 #include "dart/constraint/ConstrainedGroup.hpp"
44 #include "dart/constraint/ConstraintBase.hpp"
45 #include "dart/lcpsolver/Lemke.hpp"
46
47 namespace dart {
48 namespace constraint {
49
50 //==============================================================================
DantzigLCPSolver(double _timestep)51 DantzigLCPSolver::DantzigLCPSolver(double _timestep) : LCPSolver(_timestep)
52 {
53 // Do nothing
54 }
55
56 //==============================================================================
~DantzigLCPSolver()57 DantzigLCPSolver::~DantzigLCPSolver()
58 {
59 // Do nothing
60 }
61
62 //==============================================================================
solve(ConstrainedGroup * _group)63 void DantzigLCPSolver::solve(ConstrainedGroup* _group)
64 {
65
66 // Build LCP terms by aggregating them from constraints
67 std::size_t numConstraints = _group->getNumConstraints();
68 std::size_t n = _group->getTotalDimension();
69
70 // If there is no constraint, then just return.
71 if (0u == n)
72 return;
73
74 int nSkip = dPAD(n);
75 double* A = new double[n * nSkip];
76 double* x = new double[n];
77 double* b = new double[n];
78 double* w = new double[n];
79 double* lo = new double[n];
80 double* hi = new double[n];
81 int* findex = new int[n];
82
83 // Set w to 0 and findex to -1
84 #ifndef NDEBUG
85 std::memset(A, 0.0, n * nSkip * sizeof(double));
86 #endif
87 std::memset(w, 0.0, n * sizeof(double));
88 std::memset(findex, -1, n * sizeof(int));
89
90 // Compute offset indices
91 std::size_t* offset = new std::size_t[n];
92 offset[0] = 0;
93 // std::cout << "offset[" << 0 << "]: " << offset[0] << std::endl;
94 for (std::size_t i = 1; i < numConstraints; ++i)
95 {
96 const ConstraintBasePtr& constraint = _group->getConstraint(i - 1);
97 assert(constraint->getDimension() > 0);
98 offset[i] = offset[i - 1] + constraint->getDimension();
99 // std::cout << "offset[" << i << "]: " << offset[i] << std::endl;
100 }
101
102 // For each constraint
103 ConstraintInfo constInfo;
104 constInfo.invTimeStep = 1.0 / mTimeStep;
105 for (std::size_t i = 0; i < numConstraints; ++i)
106 {
107 const ConstraintBasePtr& constraint = _group->getConstraint(i);
108
109 constInfo.x = x + offset[i];
110 constInfo.lo = lo + offset[i];
111 constInfo.hi = hi + offset[i];
112 constInfo.b = b + offset[i];
113 constInfo.findex = findex + offset[i];
114 constInfo.w = w + offset[i];
115
116 // Fill vectors: lo, hi, b, w
117 constraint->getInformation(&constInfo);
118
119 // Fill a matrix by impulse tests: A
120 constraint->excite();
121 for (std::size_t j = 0; j < constraint->getDimension(); ++j)
122 {
123 // Adjust findex for global index
124 if (findex[offset[i] + j] >= 0)
125 findex[offset[i] + j] += offset[i];
126
127 // Apply impulse for mipulse test
128 constraint->applyUnitImpulse(j);
129
130 // Fill upper triangle blocks of A matrix
131 int index = nSkip * (offset[i] + j) + offset[i];
132 constraint->getVelocityChange(A + index, true);
133 for (std::size_t k = i + 1; k < numConstraints; ++k)
134 {
135 index = nSkip * (offset[i] + j) + offset[k];
136 _group->getConstraint(k)->getVelocityChange(A + index, false);
137 }
138
139 // Filling symmetric part of A matrix
140 for (std::size_t k = 0; k < i; ++k)
141 {
142 for (std::size_t l = 0; l < _group->getConstraint(k)->getDimension();
143 ++l)
144 {
145 int index1 = nSkip * (offset[i] + j) + offset[k] + l;
146 int index2 = nSkip * (offset[k] + l) + offset[i] + j;
147
148 A[index1] = A[index2];
149 }
150 }
151 }
152
153 assert(isSymmetric(
154 n, A, offset[i], offset[i] + constraint->getDimension() - 1));
155
156 constraint->unexcite();
157 }
158
159 assert(isSymmetric(n, A));
160
161 // Print LCP formulation
162 // dtdbg << "Before solve:" << std::endl;
163 // print(n, A, x, lo, hi, b, w, findex);
164 // std::cout << std::endl;
165
166 // Solve LCP using ODE's Dantzig algorithm
167 external::ode::dSolveLCP(n, A, x, b, w, 0, lo, hi, findex);
168
169 // Print LCP formulation
170 // dtdbg << "After solve:" << std::endl;
171 // print(n, A, x, lo, hi, b, w, findex);
172 // std::cout << std::endl;
173
174 // Apply constraint impulses
175 for (std::size_t i = 0; i < numConstraints; ++i)
176 {
177 const ConstraintBasePtr& constraint = _group->getConstraint(i);
178 constraint->applyImpulse(x + offset[i]);
179 constraint->excite();
180 }
181
182 delete[] offset;
183
184 delete[] A;
185 delete[] x;
186 delete[] b;
187 delete[] w;
188 delete[] lo;
189 delete[] hi;
190 delete[] findex;
191 }
192
193 //==============================================================================
194 #ifndef NDEBUG
isSymmetric(std::size_t _n,double * _A)195 bool DantzigLCPSolver::isSymmetric(std::size_t _n, double* _A)
196 {
197 std::size_t nSkip = dPAD(_n);
198 for (std::size_t i = 0; i < _n; ++i)
199 {
200 for (std::size_t j = 0; j < _n; ++j)
201 {
202 if (std::abs(_A[nSkip * i + j] - _A[nSkip * j + i]) > 1e-6)
203 {
204 std::cout << "A: " << std::endl;
205 for (std::size_t k = 0; k < _n; ++k)
206 {
207 for (std::size_t l = 0; l < nSkip; ++l)
208 {
209 std::cout << std::setprecision(4) << _A[k * nSkip + l] << " ";
210 }
211 std::cout << std::endl;
212 }
213
214 std::cout << "A(" << i << ", " << j << "): " << _A[nSkip * i + j]
215 << std::endl;
216 std::cout << "A(" << j << ", " << i << "): " << _A[nSkip * j + i]
217 << std::endl;
218 return false;
219 }
220 }
221 }
222
223 return true;
224 }
225
226 //==============================================================================
isSymmetric(std::size_t _n,double * _A,std::size_t _begin,std::size_t _end)227 bool DantzigLCPSolver::isSymmetric(
228 std::size_t _n, double* _A, std::size_t _begin, std::size_t _end)
229 {
230 std::size_t nSkip = dPAD(_n);
231 for (std::size_t i = _begin; i <= _end; ++i)
232 {
233 for (std::size_t j = _begin; j <= _end; ++j)
234 {
235 if (std::abs(_A[nSkip * i + j] - _A[nSkip * j + i]) > 1e-6)
236 {
237 std::cout << "A: " << std::endl;
238 for (std::size_t k = 0; k < _n; ++k)
239 {
240 for (std::size_t l = 0; l < nSkip; ++l)
241 {
242 std::cout << std::setprecision(4) << _A[k * nSkip + l] << " ";
243 }
244 std::cout << std::endl;
245 }
246
247 std::cout << "A(" << i << ", " << j << "): " << _A[nSkip * i + j]
248 << std::endl;
249 std::cout << "A(" << j << ", " << i << "): " << _A[nSkip * j + i]
250 << std::endl;
251 return false;
252 }
253 }
254 }
255
256 return true;
257 }
258
259 //==============================================================================
print(std::size_t _n,double * _A,double * _x,double *,double *,double * b,double * w,int * findex)260 void DantzigLCPSolver::print(
261 std::size_t _n,
262 double* _A,
263 double* _x,
264 double* /*lo*/,
265 double* /*hi*/,
266 double* b,
267 double* w,
268 int* findex)
269 {
270 std::size_t nSkip = dPAD(_n);
271 std::cout << "A: " << std::endl;
272 for (std::size_t i = 0; i < _n; ++i)
273 {
274 for (std::size_t j = 0; j < nSkip; ++j)
275 {
276 std::cout << std::setprecision(4) << _A[i * nSkip + j] << " ";
277 }
278 std::cout << std::endl;
279 }
280
281 std::cout << "b: ";
282 for (std::size_t i = 0; i < _n; ++i)
283 {
284 std::cout << std::setprecision(4) << b[i] << " ";
285 }
286 std::cout << std::endl;
287
288 std::cout << "w: ";
289 for (std::size_t i = 0; i < _n; ++i)
290 {
291 std::cout << w[i] << " ";
292 }
293 std::cout << std::endl;
294
295 std::cout << "x: ";
296 for (std::size_t i = 0; i < _n; ++i)
297 {
298 std::cout << _x[i] << " ";
299 }
300 std::cout << std::endl;
301
302 // std::cout << "lb: ";
303 // for (int i = 0; i < dim; ++i)
304 // {
305 // std::cout << lb[i] << " ";
306 // }
307 // std::cout << std::endl;
308
309 // std::cout << "ub: ";
310 // for (int i = 0; i < dim; ++i)
311 // {
312 // std::cout << ub[i] << " ";
313 // }
314 // std::cout << std::endl;
315
316 std::cout << "frictionIndex: ";
317 for (std::size_t i = 0; i < _n; ++i)
318 {
319 std::cout << findex[i] << " ";
320 }
321 std::cout << std::endl;
322
323 double* Ax = new double[_n];
324
325 for (std::size_t i = 0; i < _n; ++i)
326 {
327 Ax[i] = 0.0;
328 }
329
330 for (std::size_t i = 0; i < _n; ++i)
331 {
332 for (std::size_t j = 0; j < _n; ++j)
333 {
334 Ax[i] += _A[i * nSkip + j] * _x[j];
335 }
336 }
337
338 std::cout << "Ax : ";
339 for (std::size_t i = 0; i < _n; ++i)
340 {
341 std::cout << Ax[i] << " ";
342 }
343 std::cout << std::endl;
344
345 std::cout << "b + w: ";
346 for (std::size_t i = 0; i < _n; ++i)
347 {
348 std::cout << b[i] + w[i] << " ";
349 }
350 std::cout << std::endl;
351
352 delete[] Ax;
353 }
354 #endif
355
356 } // namespace constraint
357 } // namespace dart
358