Skip to content

Commit f95940d

Browse files
authored
Handle NaN fallback for Dantzig LCP (#2253)
1 parent e0f2c4e commit f95940d

File tree

3 files changed

+429
-9
lines changed

3 files changed

+429
-9
lines changed

dart/constraint/BoxedLcpConstraintSolver.cpp

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <fmt/ostream.h>
3838

3939
#include <cassert>
40+
#include <cmath>
4041

4142
#if DART_BUILD_MODE_DEBUG
4243
#include <iomanip>
@@ -149,6 +150,7 @@ void BoxedLcpConstraintSolver::solveConstrainedGroup(ConstrainedGroup& group)
149150
mA.setZero(n, nSkip);
150151
#endif
151152
mX.resize(n);
153+
mX.setZero();
152154
mB.resize(n);
153155
mW.setZero(n); // set w to 0
154156
mLo.resize(n);
@@ -267,9 +269,11 @@ void BoxedLcpConstraintSolver::solveConstrainedGroup(ConstrainedGroup& group)
267269
if (success && mX.hasNaN())
268270
success = false;
269271

272+
bool fallbackSuccess = false;
273+
bool fallbackRan = false;
270274
if (!success && mSecondaryBoxedLcpSolver) {
271275
DART_PROFILE_SCOPED_N("Secondary LCP");
272-
mSecondaryBoxedLcpSolver->solve(
276+
fallbackSuccess = mSecondaryBoxedLcpSolver->solve(
273277
n,
274278
mABackup.data(),
275279
mXBackup.data(),
@@ -280,15 +284,40 @@ void BoxedLcpConstraintSolver::solveConstrainedGroup(ConstrainedGroup& group)
280284
mFIndexBackup.data(),
281285
false);
282286
mX = mXBackup;
287+
fallbackRan = true;
283288
}
284289

285-
if (mX.hasNaN()) {
286-
DART_ERROR(
287-
"[BoxedLcpConstraintSolver] The solution of LCP includes NAN values: "
288-
"{}. We're setting it zero for safety. Consider using more robust "
289-
"solver such as PGS as a secondary solver. If this happens even with "
290-
"PGS solver, please report this as a bug.",
291-
fmt::streamed(mX.transpose()));
290+
const bool hasNaN = mX.hasNaN();
291+
if (!success && fallbackRan && hasNaN) {
292+
// If the fallback produced NaNs, zero just those entries but still allow
293+
// non-NaN entries to propagate.
294+
for (int i = 0; i < mX.size(); ++i) {
295+
if (std::isnan(mX[i]))
296+
mX[i] = 0.0;
297+
}
298+
}
299+
300+
// Treat a finite fallback solution as usable even if the solver reported
301+
// failure to avoid discarding potentially valid impulses.
302+
const bool finalSuccess
303+
= success || fallbackSuccess || (fallbackRan && !mX.hasNaN());
304+
305+
if (!finalSuccess) {
306+
if (hasNaN) {
307+
DART_ERROR(
308+
"[BoxedLcpConstraintSolver] The solution of LCP includes NAN values: "
309+
"{}. We're setting it zero for safety. Consider using more robust "
310+
"solver such as PGS as a secondary solver. If this happens even with "
311+
"PGS solver, please report this as a bug.",
312+
fmt::streamed(mX.transpose()));
313+
} else {
314+
DART_ERROR(
315+
"[BoxedLcpConstraintSolver] Primary LCP solver failed to find a "
316+
"solution. The constraint impulses are set to zero for safety. "
317+
"Consider configuring a secondary solver (e.g., PGS) to provide a "
318+
"fallback when Dantzig fails.");
319+
}
320+
292321
mX.setZero();
293322
}
294323

dart/constraint/ConstrainedGroup.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737

3838
#include <dart/constraint/Fwd.hpp>
3939

40+
#include <dart/Export.hpp>
41+
4042
#include <Eigen/Dense>
4143

4244
#include <memory>
@@ -57,7 +59,7 @@ class ConstraintSolver;
5759
/// ConstrainedGroup is a group of skeletons that interact each other with
5860
/// constraints
5961
/// @sa class ConstraintSolver
60-
class ConstrainedGroup
62+
class DART_API ConstrainedGroup
6163
{
6264
public:
6365
//----------------------------------------------------------------------------

0 commit comments

Comments
 (0)