Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow BoxedLcpConstraintSolver to have secondary LCP solver #1265

Merged
merged 12 commits into from
Apr 8, 2019
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* Dynamics

* Fixed incorrect transpose check in Inertia::verifySpatialTensor(): [#1258](https://github.com/dartsim/dart/pull/1258)
* Allowed BoxedLcpConstraintSolver to have a secondary LCP solver: [#1265](https://github.com/dartsim/dart/pull/1265)

* Simulation

Expand Down
2 changes: 1 addition & 1 deletion dart/collision/CollisionDetector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class CollisionDetector : public std::enable_shared_from_this<CollisionDetector>

/// \brief Create a clone of this CollisionDetector. All the properties will
/// be copied over, but not collision objects.
virtual std::shared_ptr<CollisionDetector> cloneWithoutCollisionObjects() = 0;
virtual std::shared_ptr<CollisionDetector> cloneWithoutCollisionObjects() const = 0;

/// Return collision detection engine type as a std::string
virtual const std::string& getType() const = 0;
Expand Down
2 changes: 1 addition & 1 deletion dart/collision/bullet/BulletCollisionDetector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ BulletCollisionDetector::~BulletCollisionDetector()

//==============================================================================
std::shared_ptr<CollisionDetector>
BulletCollisionDetector::cloneWithoutCollisionObjects()
BulletCollisionDetector::cloneWithoutCollisionObjects() const
{
return BulletCollisionDetector::create();
}
Expand Down
3 changes: 2 additions & 1 deletion dart/collision/bullet/BulletCollisionDetector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ class BulletCollisionDetector : public CollisionDetector
virtual ~BulletCollisionDetector();

// Documentation inherited
std::shared_ptr<CollisionDetector> cloneWithoutCollisionObjects() override;
std::shared_ptr<CollisionDetector> cloneWithoutCollisionObjects() const
override;

// Documentation inherited
const std::string& getType() const override;
Expand Down
2 changes: 1 addition & 1 deletion dart/collision/dart/DARTCollisionDetector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ std::shared_ptr<DARTCollisionDetector> DARTCollisionDetector::create()

//==============================================================================
std::shared_ptr<CollisionDetector>
DARTCollisionDetector::cloneWithoutCollisionObjects()
DARTCollisionDetector::cloneWithoutCollisionObjects() const
{
return DARTCollisionDetector::create();
}
Expand Down
3 changes: 2 additions & 1 deletion dart/collision/dart/DARTCollisionDetector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ class DARTCollisionDetector : public CollisionDetector
static std::shared_ptr<DARTCollisionDetector> create();

// Documentation inherited
std::shared_ptr<CollisionDetector> cloneWithoutCollisionObjects() override;
std::shared_ptr<CollisionDetector> cloneWithoutCollisionObjects() const
override;

// Documentation inherited
const std::string& getType() const override;
Expand Down
2 changes: 1 addition & 1 deletion dart/collision/fcl/FCLCollisionDetector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ FCLCollisionDetector::~FCLCollisionDetector()

//==============================================================================
std::shared_ptr<CollisionDetector>
FCLCollisionDetector::cloneWithoutCollisionObjects()
FCLCollisionDetector::cloneWithoutCollisionObjects() const
{
return FCLCollisionDetector::create();
}
Expand Down
3 changes: 2 additions & 1 deletion dart/collision/fcl/FCLCollisionDetector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ class FCLCollisionDetector : public CollisionDetector
virtual ~FCLCollisionDetector();

// Documentation inherited
std::shared_ptr<CollisionDetector> cloneWithoutCollisionObjects() override;
std::shared_ptr<CollisionDetector> cloneWithoutCollisionObjects() const
override;

// Documentation inherited
const std::string& getType() const override;
Expand Down
2 changes: 1 addition & 1 deletion dart/collision/ode/OdeCollisionDetector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ OdeCollisionDetector::~OdeCollisionDetector()

//==============================================================================
std::shared_ptr<CollisionDetector>
OdeCollisionDetector::cloneWithoutCollisionObjects()
OdeCollisionDetector::cloneWithoutCollisionObjects() const
{
return OdeCollisionDetector::create();
}
Expand Down
3 changes: 2 additions & 1 deletion dart/collision/ode/OdeCollisionDetector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ class OdeCollisionDetector : public CollisionDetector
virtual ~OdeCollisionDetector();

// Documentation inherited
std::shared_ptr<CollisionDetector> cloneWithoutCollisionObjects() override;
std::shared_ptr<CollisionDetector> cloneWithoutCollisionObjects() const
override;

// Documentation inherited
const std::string& getType() const override;
Expand Down
127 changes: 119 additions & 8 deletions dart/constraint/BoxedLcpConstraintSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,59 @@
#include "dart/external/odelcpsolver/lcp.h"

#include "dart/common/Console.hpp"
#include "dart/constraint/ConstrainedGroup.hpp"
#include "dart/constraint/ConstraintBase.hpp"
#include "dart/constraint/DantzigBoxedLcpSolver.hpp"
#include "dart/constraint/PgsBoxedLcpSolver.hpp"
#include "dart/lcpsolver/Lemke.hpp"

namespace dart {
namespace constraint {

//==============================================================================
BoxedLcpConstraintSolver::BoxedLcpConstraintSolver(
double timeStep, BoxedLcpSolverPtr boxedLcpSolver)
: ConstraintSolver(timeStep), mBoxedLcpSolver(std::move(boxedLcpSolver))
double timeStep,
BoxedLcpSolverPtr boxedLcpSolver,
BoxedLcpSolverPtr secondaryBoxedLcpSolver)
: BoxedLcpConstraintSolver(
std::move(boxedLcpSolver), std::move(secondaryBoxedLcpSolver))
{
if (!mBoxedLcpSolver)
mBoxedLcpSolver = std::make_shared<DantzigBoxedLcpSolver>();
setTimeStep(timeStep);
}

//==============================================================================
BoxedLcpConstraintSolver::BoxedLcpConstraintSolver()
: BoxedLcpConstraintSolver(std::make_shared<DantzigBoxedLcpSolver>())
{
// Do nothing
}

//==============================================================================
BoxedLcpConstraintSolver::BoxedLcpConstraintSolver(
BoxedLcpSolverPtr boxedLcpSolver)
: BoxedLcpConstraintSolver(
std::move(boxedLcpSolver), std::make_shared<PgsBoxedLcpSolver>())
{
// Do nothing
}

//==============================================================================
BoxedLcpConstraintSolver::BoxedLcpConstraintSolver(
BoxedLcpSolverPtr boxedLcpSolver, BoxedLcpSolverPtr secondaryBoxedLcpSolver)
: ConstraintSolver()
{
if (boxedLcpSolver)
{
setBoxedLcpSolver(std::move(boxedLcpSolver));
}
else
{
dtwarn << "[BoxedLcpConstraintSolver] Attempting to construct with nullptr "
<< "LCP solver, which is not allowed. Using Dantzig solver "
<< "instead.\n";
setBoxedLcpSolver(std::make_shared<DantzigBoxedLcpSolver>());
}

setSecondaryBoxedLcpSolver(std::move(secondaryBoxedLcpSolver));
}

//==============================================================================
Expand All @@ -68,6 +106,13 @@ void BoxedLcpConstraintSolver::setBoxedLcpSolver(BoxedLcpSolverPtr lcpSolver)
return;
}

if (lcpSolver == mSecondaryBoxedLcpSolver)
{
dtwarn << "[BoxedLcpConstraintSolver::setBoxedLcpSolver] Attempting to set "
<< "a primary LCP solver that is the same with the secondary LCP "
<< "solver, which is discouraged. Ignoring this request.\n";
}

mBoxedLcpSolver = std::move(lcpSolver);
}

Expand All @@ -77,6 +122,28 @@ ConstBoxedLcpSolverPtr BoxedLcpConstraintSolver::getBoxedLcpSolver() const
return mBoxedLcpSolver;
}

//==============================================================================
void BoxedLcpConstraintSolver::setSecondaryBoxedLcpSolver(
BoxedLcpSolverPtr lcpSolver)
{
if (lcpSolver == mBoxedLcpSolver)
{
dtwarn << "[BoxedLcpConstraintSolver::setBoxedLcpSolver] Attempting to set "
<< "the secondary LCP solver that is identical to the primary LCP "
<< "solver, which is redundant. Please use different solvers or set "
<< "the secondary LCP solver to nullptr.\n";
}

mSecondaryBoxedLcpSolver = std::move(lcpSolver);
}

//==============================================================================
ConstBoxedLcpSolverPtr BoxedLcpConstraintSolver::getSecondaryBoxedLcpSolver()
const
{
return mSecondaryBoxedLcpSolver;
}

//==============================================================================
void BoxedLcpConstraintSolver::solveConstrainedGroup(ConstrainedGroup& group)
{
Expand Down Expand Up @@ -173,17 +240,61 @@ void BoxedLcpConstraintSolver::solveConstrainedGroup(ConstrainedGroup& group)
// print(n, A, x, lo, hi, b, w, findex);
// std::cout << std::endl;

// Solve LCP using ODE's Dantzig algorithm
// Solve LCP using the primary solver and fallback to secondary solver when
// the parimary solver failed.
if (mSecondaryBoxedLcpSolver)
{
// Make backups for the secondary LCP solver because the primary solver
// modifies the original terms.
mABackup = mA;
mXBackup = mX;
mBBackup = mB;
mLoBackup = mLo;
mHiBackup = mHi;
mFIndexBackup = mFIndex;
}
const bool earlyTermination = (mSecondaryBoxedLcpSolver != nullptr);
assert(mBoxedLcpSolver);
mBoxedLcpSolver->solve(
bool success = mBoxedLcpSolver->solve(
n,
mA.data(),
mX.data(),
mB.data(),
0,
mLo.data(),
mHi.data(),
mFIndex.data());
mFIndex.data(),
earlyTermination);

// Sanity check. LCP solvers should not report success with nan values, but
// it could happen. So we set the sucees to false for nan values.
if (success && mX.hasNaN())
success = false;

if (!success && mSecondaryBoxedLcpSolver)
{
mSecondaryBoxedLcpSolver->solve(
n,
mABackup.data(),
mXBackup.data(),
mBBackup.data(),
0,
mLoBackup.data(),
mHiBackup.data(),
mFIndexBackup.data(),
false);
mX = mXBackup;
}

if (mX.hasNaN())
{
dterr << "[BoxedLcpConstraintSolver] The solution of LCP includes NAN "
<< "values: " << mX.transpose() << ". We're setting it zero for "
<< "safety. Consider using more robust solver such as PGS as a "
<< "secondary solver. If this happens even with PGS solver, please "
<< "report this as a bug.\n";
mX.setZero();
}

// Print LCP formulation
// dtdbg << "After solve:" << std::endl;
Expand Down
73 changes: 72 additions & 1 deletion dart/constraint/BoxedLcpConstraintSolver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,43 +43,114 @@ class BoxedLcpConstraintSolver : public ConstraintSolver
{
public:
/// Constructor
///
/// \param[in] timeStep Simulation time step
/// \param[in] boxedLcpSolver The primary boxed LCP solver. When nullptr is
/// passed, Dantzig solver will be used.
/// \param[in] secondaryBoxedLcpSolver The secondary boxed-LCP solver. When
/// nullptr is passed, PGS solver will be used. This is to make the default
/// solver setting to be Dantzig + PGS. In order to disable use of secondary
/// solver, call setSecondaryBoxedLcpSolver(nullptr) explicitly.
///
/// \deprecated Deprecated in DART 6.8. Please use other constructors that
/// doesn't take timespte. Timestep should be set by the owner of this solver
/// such as dart::simulation::World when the solver added.
DART_DEPRECATED(6.8)
BoxedLcpConstraintSolver(
double timeStep, BoxedLcpSolverPtr boxedLcpSolver = nullptr);
double timeStep,
BoxedLcpSolverPtr boxedLcpSolver,
BoxedLcpSolverPtr secondaryBoxedLcpSolver);

/// Constructos with default primary and secondary LCP solvers, which are
/// Dantzig and PGS, respectively.
BoxedLcpConstraintSolver();

/// Constructors with specific primary LCP solver.
///
/// \param[in] boxedLcpSolver The primary boxed LCP solver. When nullptr is
/// passed, which is discouraged, Dantzig solver will be used.
BoxedLcpConstraintSolver(BoxedLcpSolverPtr boxedLcpSolver);

/// Constructs with specific primary and secondary LCP solvers.
///
/// \param[in] boxedLcpSolver The primary boxed LCP solver. When nullptr is
/// passed, which is discouraged, Dantzig solver will be used.
/// \param[in] secondaryBoxedLcpSolver The secondary boxed-LCP solver. Pass
/// nullptr to disable using secondary LCP solver.
BoxedLcpConstraintSolver(
BoxedLcpSolverPtr boxedLcpSolver,
BoxedLcpSolverPtr secondaryBoxedLcpSolver);

/// Sets boxed LCP (BLCP) solver
///
/// \param[in] boxedLcpSolver The primary boxed LCP solver. When nullptr is
/// passed, Dantzig solver will be used.
void setBoxedLcpSolver(BoxedLcpSolverPtr lcpSolver);

/// Returns boxed LCP (BLCP) solver
ConstBoxedLcpSolverPtr getBoxedLcpSolver() const;

/// Sets boxed LCP (BLCP) solver that is used when the primary solver failed
void setSecondaryBoxedLcpSolver(BoxedLcpSolverPtr lcpSolver);

/// Returns boxed LCP (BLCP) solver that is used when the primary solver
/// failed
ConstBoxedLcpSolverPtr getSecondaryBoxedLcpSolver() const;

protected:
// Documentation inherited.
void solveConstrainedGroup(ConstrainedGroup& group) override;

/// Boxed LCP solver
BoxedLcpSolverPtr mBoxedLcpSolver;
// TODO(JS): Hold as unique_ptr because there is no reason to share. Make this
// change in DART 7 because it's API breaking change.

/// Boxed LCP solver to be used when the primary solver failed
BoxedLcpSolverPtr mSecondaryBoxedLcpSolver;
// TODO(JS): Hold as unique_ptr because there is no reason to share. Make this
// change in DART 7 because it's API breaking change.

/// Cache data for boxed LCP formulation
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> mA;

/// Cache data for boxed LCP formulation
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>
mABackup;

/// Cache data for boxed LCP formulation
Eigen::VectorXd mX;

/// Cache data for boxed LCP formulation
Eigen::VectorXd mXBackup;

/// Cache data for boxed LCP formulation
Eigen::VectorXd mB;

/// Cache data for boxed LCP formulation
Eigen::VectorXd mBBackup;

/// Cache data for boxed LCP formulation
Eigen::VectorXd mW;

/// Cache data for boxed LCP formulation
Eigen::VectorXd mLo;

/// Cache data for boxed LCP formulation
Eigen::VectorXd mLoBackup;

/// Cache data for boxed LCP formulation
Eigen::VectorXd mHi;

/// Cache data for boxed LCP formulation
Eigen::VectorXd mHiBackup;

/// Cache data for boxed LCP formulation
Eigen::VectorXi mFIndex;

/// Cache data for boxed LCP formulation
Eigen::VectorXi mFIndexBackup;

/// Cache data for boxed LCP formulation
Eigen::VectorXi mOffset;

Expand Down
Loading