diff --git a/dart/constraint/BallJointConstraint.cpp b/dart/constraint/BallJointConstraint.cpp index 459837da3701f..10305c55ff103 100644 --- a/dart/constraint/BallJointConstraint.cpp +++ b/dart/constraint/BallJointConstraint.cpp @@ -35,7 +35,7 @@ #include "dart/dynamics/BodyNode.hpp" #include "dart/dynamics/Skeleton.hpp" #include "dart/math/Constants.hpp" -#include "dart/math/lcp/Dantzig/Lcp.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" #include diff --git a/dart/constraint/BoxedLcpConstraintSolver.cpp b/dart/constraint/BoxedLcpConstraintSolver.cpp index 399f97b4827cf..78297a93314e1 100644 --- a/dart/constraint/BoxedLcpConstraintSolver.cpp +++ b/dart/constraint/BoxedLcpConstraintSolver.cpp @@ -48,8 +48,8 @@ #include "dart/constraint/ConstraintBase.hpp" #include "dart/constraint/DantzigBoxedLcpSolver.hpp" #include "dart/constraint/PgsBoxedLcpSolver.hpp" -#include "dart/math/lcp/Dantzig/Lcp.hpp" #include "dart/math/lcp/Lemke.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" namespace dart { namespace constraint { diff --git a/dart/constraint/ContactConstraint.cpp b/dart/constraint/ContactConstraint.cpp index e62a93a1db3a0..94fe3d13b84fe 100644 --- a/dart/constraint/ContactConstraint.cpp +++ b/dart/constraint/ContactConstraint.cpp @@ -39,7 +39,7 @@ #include "dart/dynamics/Skeleton.hpp" #include "dart/math/Constants.hpp" #include "dart/math/Helpers.hpp" -#include "dart/math/lcp/Dantzig/Lcp.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" #include diff --git a/dart/constraint/DantzigBoxedLcpSolver.cpp b/dart/constraint/DantzigBoxedLcpSolver.cpp index 3059a3b59d053..b2299328ce1a4 100644 --- a/dart/constraint/DantzigBoxedLcpSolver.cpp +++ b/dart/constraint/DantzigBoxedLcpSolver.cpp @@ -33,7 +33,7 @@ #include "dart/constraint/DantzigBoxedLcpSolver.hpp" #include "dart/common/Profile.hpp" -#include "dart/math/lcp/Dantzig/Lcp.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" namespace dart { namespace constraint { diff --git a/dart/constraint/DantzigLCPSolver.cpp b/dart/constraint/DantzigLCPSolver.cpp index fe47df4e70b62..bc034af489fb3 100644 --- a/dart/constraint/DantzigLCPSolver.cpp +++ b/dart/constraint/DantzigLCPSolver.cpp @@ -42,8 +42,8 @@ #include "dart/common/Logging.hpp" #include "dart/constraint/ConstrainedGroup.hpp" #include "dart/constraint/ConstraintBase.hpp" -#include "dart/math/lcp/Dantzig/Lcp.hpp" #include "dart/math/lcp/Lemke.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" namespace dart { namespace constraint { diff --git a/dart/constraint/JointConstraint.cpp b/dart/constraint/JointConstraint.cpp index e6e45ac528474..c03e84124983c 100644 --- a/dart/constraint/JointConstraint.cpp +++ b/dart/constraint/JointConstraint.cpp @@ -38,7 +38,7 @@ #include "dart/dynamics/Joint.hpp" #include "dart/dynamics/Skeleton.hpp" #include "dart/math/Constants.hpp" -#include "dart/math/lcp/Dantzig/Lcp.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" #include diff --git a/dart/constraint/JointLimitConstraint.cpp b/dart/constraint/JointLimitConstraint.cpp index f1eb4af548e51..80cff78523991 100644 --- a/dart/constraint/JointLimitConstraint.cpp +++ b/dart/constraint/JointLimitConstraint.cpp @@ -38,7 +38,7 @@ #include "dart/dynamics/Joint.hpp" #include "dart/dynamics/Skeleton.hpp" #include "dart/math/Constants.hpp" -#include "dart/math/lcp/Dantzig/Lcp.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" #include diff --git a/dart/constraint/MimicMotorConstraint.cpp b/dart/constraint/MimicMotorConstraint.cpp index aa135cab871b2..dd07238608836 100644 --- a/dart/constraint/MimicMotorConstraint.cpp +++ b/dart/constraint/MimicMotorConstraint.cpp @@ -37,7 +37,7 @@ #include "dart/dynamics/BodyNode.hpp" #include "dart/dynamics/Joint.hpp" #include "dart/dynamics/Skeleton.hpp" -#include "dart/math/lcp/Dantzig/Lcp.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" #include diff --git a/dart/constraint/PGSLCPSolver.cpp b/dart/constraint/PGSLCPSolver.cpp index 9aa85b5eedeed..0b5f51a513554 100644 --- a/dart/constraint/PGSLCPSolver.cpp +++ b/dart/constraint/PGSLCPSolver.cpp @@ -43,8 +43,8 @@ #include "dart/common/Profile.hpp" #include "dart/constraint/ConstrainedGroup.hpp" #include "dart/constraint/ConstraintBase.hpp" -#include "dart/math/lcp/Dantzig/Lcp.hpp" #include "dart/math/lcp/Lemke.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" namespace dart { namespace constraint { diff --git a/dart/constraint/PgsBoxedLcpSolver.cpp b/dart/constraint/PgsBoxedLcpSolver.cpp index 1810862b36c53..9845260f6801e 100644 --- a/dart/constraint/PgsBoxedLcpSolver.cpp +++ b/dart/constraint/PgsBoxedLcpSolver.cpp @@ -33,8 +33,8 @@ #include "dart/constraint/PgsBoxedLcpSolver.hpp" #include "dart/math/Constants.hpp" -#include "dart/math/lcp/Dantzig/Matrix.hpp" -#include "dart/math/lcp/Dantzig/Misc.hpp" +#include "dart/math/lcp/dantzig/Matrix.hpp" +#include "dart/math/lcp/dantzig/Misc.hpp" #include diff --git a/dart/constraint/ServoMotorConstraint.cpp b/dart/constraint/ServoMotorConstraint.cpp index 81b658c9c29e5..453c0cb4afd33 100644 --- a/dart/constraint/ServoMotorConstraint.cpp +++ b/dart/constraint/ServoMotorConstraint.cpp @@ -37,7 +37,7 @@ #include "dart/dynamics/BodyNode.hpp" #include "dart/dynamics/Joint.hpp" #include "dart/dynamics/Skeleton.hpp" -#include "dart/math/lcp/Dantzig/Lcp.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" #include diff --git a/dart/constraint/SoftContactConstraint.cpp b/dart/constraint/SoftContactConstraint.cpp index e3a16495fac29..5149934ecdb87 100644 --- a/dart/constraint/SoftContactConstraint.cpp +++ b/dart/constraint/SoftContactConstraint.cpp @@ -43,7 +43,7 @@ #include "dart/dynamics/SoftMeshShape.hpp" #include "dart/math/Constants.hpp" #include "dart/math/Helpers.hpp" -#include "dart/math/lcp/Dantzig/Lcp.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" #include diff --git a/dart/constraint/WeldJointConstraint.cpp b/dart/constraint/WeldJointConstraint.cpp index 39f29f724843c..feb53309a6a3b 100644 --- a/dart/constraint/WeldJointConstraint.cpp +++ b/dart/constraint/WeldJointConstraint.cpp @@ -36,7 +36,7 @@ #include "dart/dynamics/BodyNode.hpp" #include "dart/dynamics/Skeleton.hpp" #include "dart/math/Constants.hpp" -#include "dart/math/lcp/Dantzig/Lcp.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" namespace dart { namespace constraint { diff --git a/dart/lcpsolver/dantzig/PivotMatrix.hpp b/dart/lcpsolver/dantzig/PivotMatrix.hpp index 9c84271caa2e3..066cc76f4f7bd 100644 --- a/dart/lcpsolver/dantzig/PivotMatrix.hpp +++ b/dart/lcpsolver/dantzig/PivotMatrix.hpp @@ -1,4 +1,4 @@ #pragma once #include "dart/lcpsolver/detail/DeprecatedNamespace.hpp" -#include "dart/math/lcp/Dantzig/PivotMatrix.hpp" +#include "dart/math/lcp/dantzig/PivotMatrix.hpp" diff --git a/dart/lcpsolver/dantzig/common.h b/dart/lcpsolver/dantzig/common.h index 49684852873d2..2d8abd649fd06 100644 --- a/dart/lcpsolver/dantzig/common.h +++ b/dart/lcpsolver/dantzig/common.h @@ -1,4 +1,4 @@ #pragma once #include "dart/lcpsolver/detail/DeprecatedNamespace.hpp" -#include "dart/math/lcp/Dantzig/Common.hpp" +#include "dart/math/lcp/dantzig/Common.hpp" diff --git a/dart/lcpsolver/dantzig/lcp-impl.hpp b/dart/lcpsolver/dantzig/lcp-impl.hpp index ca6c50e92f3b6..2448e0eb29e8e 100644 --- a/dart/lcpsolver/dantzig/lcp-impl.hpp +++ b/dart/lcpsolver/dantzig/lcp-impl.hpp @@ -1,4 +1,4 @@ #pragma once #include "dart/lcpsolver/detail/DeprecatedNamespace.hpp" -#include "dart/math/lcp/Dantzig/Lcp-impl.hpp" +#include "dart/math/lcp/dantzig/Lcp-impl.hpp" diff --git a/dart/lcpsolver/dantzig/lcp.h b/dart/lcpsolver/dantzig/lcp.h index 1eef050ab1a46..1bd890749d399 100644 --- a/dart/lcpsolver/dantzig/lcp.h +++ b/dart/lcpsolver/dantzig/lcp.h @@ -1,4 +1,4 @@ #pragma once #include "dart/lcpsolver/detail/DeprecatedNamespace.hpp" -#include "dart/math/lcp/Dantzig/Lcp.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" diff --git a/dart/lcpsolver/dantzig/matrix-impl.hpp b/dart/lcpsolver/dantzig/matrix-impl.hpp index bdb4953ab3174..bdb357bd41046 100644 --- a/dart/lcpsolver/dantzig/matrix-impl.hpp +++ b/dart/lcpsolver/dantzig/matrix-impl.hpp @@ -1,4 +1,4 @@ #pragma once #include "dart/lcpsolver/detail/DeprecatedNamespace.hpp" -#include "dart/math/lcp/Dantzig/Matrix-impl.hpp" +#include "dart/math/lcp/dantzig/Matrix-impl.hpp" diff --git a/dart/lcpsolver/dantzig/matrix.h b/dart/lcpsolver/dantzig/matrix.h index 5e153350ec3fa..1a542c2889892 100644 --- a/dart/lcpsolver/dantzig/matrix.h +++ b/dart/lcpsolver/dantzig/matrix.h @@ -1,4 +1,4 @@ #pragma once #include "dart/lcpsolver/detail/DeprecatedNamespace.hpp" -#include "dart/math/lcp/Dantzig/Matrix.hpp" +#include "dart/math/lcp/dantzig/Matrix.hpp" diff --git a/dart/lcpsolver/dantzig/misc.h b/dart/lcpsolver/dantzig/misc.h index a088b08548d61..e18903490f169 100644 --- a/dart/lcpsolver/dantzig/misc.h +++ b/dart/lcpsolver/dantzig/misc.h @@ -1,4 +1,4 @@ #pragma once #include "dart/lcpsolver/detail/DeprecatedNamespace.hpp" -#include "dart/math/lcp/Dantzig/Misc.hpp" +#include "dart/math/lcp/dantzig/Misc.hpp" diff --git a/dart/lcpsolver/detail/DeprecatedNamespace.hpp b/dart/lcpsolver/detail/DeprecatedNamespace.hpp index e20130e7f20aa..2cf9169edd455 100644 --- a/dart/lcpsolver/detail/DeprecatedNamespace.hpp +++ b/dart/lcpsolver/detail/DeprecatedNamespace.hpp @@ -16,14 +16,12 @@ namespace dart { namespace math { namespace lcp { +using namespace ::dart::math; } // namespace lcp } // namespace math -} // namespace dart - -namespace dart { namespace - [[deprecated("dart::lcpsolver is deprecated; include dart/math/lcp headers " - "and use dart::math instead")]] lcpsolver { + [[deprecated("dart::lcpsolver is deprecated; include dart/math/lcp " + "headers and use dart::math instead")]] lcpsolver { using namespace math::lcp; } // namespace lcpsolver } // namespace dart diff --git a/dart/math/lcp/All.hpp b/dart/math/lcp/All.hpp index 82d5fbfd4832a..e446e62526e4a 100644 --- a/dart/math/lcp/All.hpp +++ b/dart/math/lcp/All.hpp @@ -1,5 +1,13 @@ #pragma once -#include "dart/math/lcp/Dantzig/Lcp.hpp" -#include "dart/math/lcp/Lemke.hpp" -#include "dart/math/lcp/ODELCPSolver.hpp" +// New LCP solver framework (v2) +#include +#include + +// Pivoting methods +#include + +// Legacy LCP solvers (v1 - backward compatibility) +#include +#include +#include diff --git a/dart/math/lcp/CMakeLists.txt b/dart/math/lcp/CMakeLists.txt index a548afeb93920..5acafb146dd1d 100644 --- a/dart/math/lcp/CMakeLists.txt +++ b/dart/math/lcp/CMakeLists.txt @@ -5,12 +5,36 @@ dart_add_core_headers(${math_lcp_hdrs}) dart_add_core_sources(${math_lcp_srcs}) # Dantzig implementation headers and sources (remain public API) -file(GLOB math_lcp_dantzig_hdrs "Dantzig/*.hpp") -file(GLOB math_lcp_dantzig_srcs "Dantzig/*.cpp") +file(GLOB math_lcp_dantzig_hdrs "dantzig/*.hpp") +file(GLOB math_lcp_dantzig_srcs "dantzig/*.cpp") dart_add_core_headers(${math_lcp_dantzig_hdrs}) dart_add_core_sources(${math_lcp_dantzig_srcs}) -# Compute relative header names (e.g., lcp/Lemke.hpp, lcp/Dantzig/Common.hpp) +# Pivoting methods (Lemke, Dantzig wrappers, etc.) +file(GLOB math_lcp_pivoting_hdrs "pivoting/*.hpp") +file(GLOB math_lcp_pivoting_srcs "pivoting/*.cpp") +dart_add_core_headers(${math_lcp_pivoting_hdrs}) +dart_add_core_sources(${math_lcp_pivoting_srcs}) + +# Projection methods (PGS, PSOR, BGS, etc. - future) +file(GLOB math_lcp_projection_hdrs "projection/*.hpp") +file(GLOB math_lcp_projection_srcs "projection/*.cpp") +dart_add_core_headers(${math_lcp_projection_hdrs}) +dart_add_core_sources(${math_lcp_projection_srcs}) + +# Newton methods (future) +file(GLOB math_lcp_newton_hdrs "newton/*.hpp") +file(GLOB math_lcp_newton_srcs "newton/*.cpp") +dart_add_core_headers(${math_lcp_newton_hdrs}) +dart_add_core_sources(${math_lcp_newton_srcs}) + +# Other methods (interior point, etc. - future) +file(GLOB math_lcp_other_hdrs "other/*.hpp") +file(GLOB math_lcp_other_srcs "other/*.cpp") +dart_add_core_headers(${math_lcp_other_hdrs}) +dart_add_core_sources(${math_lcp_other_srcs}) + +# Compute relative header names (e.g., lcp/Lemke.hpp, lcp/dantzig/Common.hpp) set(math_lcp_header_names "") foreach(header ${math_lcp_hdrs}) file(RELATIVE_PATH rel_path "${CMAKE_CURRENT_SOURCE_DIR}" ${header}) @@ -29,8 +53,47 @@ install( COMPONENT headers ) +install( + FILES ${math_lcp_dantzig_hdrs} + DESTINATION include/dart/math/lcp/dantzig + COMPONENT headers +) + +# Compatibility install for legacy Dantzig include path install( FILES ${math_lcp_dantzig_hdrs} DESTINATION include/dart/math/lcp/Dantzig COMPONENT headers ) + +if(math_lcp_pivoting_hdrs) + install( + FILES ${math_lcp_pivoting_hdrs} + DESTINATION include/dart/math/lcp/pivoting + COMPONENT headers + ) +endif() + +if(math_lcp_projection_hdrs) + install( + FILES ${math_lcp_projection_hdrs} + DESTINATION include/dart/math/lcp/projection + COMPONENT headers + ) +endif() + +if(math_lcp_newton_hdrs) + install( + FILES ${math_lcp_newton_hdrs} + DESTINATION include/dart/math/lcp/newton + COMPONENT headers + ) +endif() + +if(math_lcp_other_hdrs) + install( + FILES ${math_lcp_other_hdrs} + DESTINATION include/dart/math/lcp/other + COMPONENT headers + ) +endif() diff --git a/dart/math/lcp/LcpSolver.cpp b/dart/math/lcp/LcpSolver.cpp new file mode 100644 index 0000000000000..6f837fd63b49a --- /dev/null +++ b/dart/math/lcp/LcpSolver.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011-2025, The DART development contributors + * All rights reserved. + * + * The list of contributors can be found at: + * https://github.com/dartsim/dart/blob/main/LICENSE + * + * This file is provided under the following "BSD-style" License: + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "dart/math/lcp/LcpSolver.hpp" + +namespace dart { +namespace math { + +//============================================================================== +LcpResult LcpSolver::solve( + const Eigen::MatrixXd& A, const Eigen::VectorXd& b, Eigen::VectorXd& x) +{ + return solve(A, b, x, mDefaultOptions); +} + +//============================================================================== +LcpOptions LcpSolver::getDefaultOptions() const +{ + return mDefaultOptions; +} + +//============================================================================== +void LcpSolver::setDefaultOptions(const LcpOptions& options) +{ + mDefaultOptions = options; +} + +} // namespace math +} // namespace dart diff --git a/dart/math/lcp/LcpSolver.hpp b/dart/math/lcp/LcpSolver.hpp new file mode 100644 index 0000000000000..ff2471729bb16 --- /dev/null +++ b/dart/math/lcp/LcpSolver.hpp @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2011-2025, The DART development contributors + * All rights reserved. + * + * The list of contributors can be found at: + * https://github.com/dartsim/dart/blob/main/LICENSE + * + * This file is provided under the following "BSD-style" License: + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DART_MATH_LCP_LCPSOLVER_HPP_ +#define DART_MATH_LCP_LCPSOLVER_HPP_ + +#include + +#include + +#include + +#include +#include +#include + +namespace dart { +namespace math { + +//============================================================================== +/// Base class for LCP solvers +/// +/// This provides a common interface for all LCP solvers. Solvers can implement +/// different algorithms (pivoting, projection, Newton, etc.) while maintaining +/// a consistent API. +/// +/// Problem formulation: +/// Find x such that: +/// w = Ax + b +/// w >= 0, x >= 0 +/// x^T * w = 0 (complementarity) +/// +/// For bounded problems (BLCP): +/// l <= x <= u +/// with complementarity on bounds +class DART_API LcpSolver +{ +public: + /// Virtual destructor + virtual ~LcpSolver() = default; + + /// Solve the LCP problem + /// + /// \param[in] A Coefficient matrix (n x n) + /// \param[in] b Right-hand side vector (n) + /// \param[out] x Solution vector (n) + /// \return Result structure with status and statistics + /// + /// \note Default behavior: calls solve() with default options + virtual LcpResult solve( + const Eigen::MatrixXd& A, const Eigen::VectorXd& b, Eigen::VectorXd& x); + + /// Solve the LCP problem with options + /// + /// \param[in] A Coefficient matrix (n x n) + /// \param[in] b Right-hand side vector (n) + /// \param[in,out] x Solution vector (n), can be used as initial guess if + /// warmStart=true + /// \param[in] options Solver options + /// \return Result structure with status and statistics + virtual LcpResult solve( + const Eigen::MatrixXd& A, + const Eigen::VectorXd& b, + Eigen::VectorXd& x, + const LcpOptions& options) + = 0; + + /// Get the solver name + /// + /// \return Name of the solver (e.g., "Lemke", "Dantzig") + virtual std::string getName() const = 0; + + /// Get the solver category + /// + /// \return Category name (e.g., "Pivoting", "Projection", "Newton") + virtual std::string getCategory() const = 0; + + /// Get default options for this solver + /// + /// \return Default LcpOptions + virtual LcpOptions getDefaultOptions() const; + + /// Set default options for this solver + /// + /// \param[in] options New default options + virtual void setDefaultOptions(const LcpOptions& options); + +protected: + /// Default options for this solver instance + LcpOptions mDefaultOptions; +}; + +//============================================================================== +/// Shared pointer type for LcpSolver +using LcpSolverPtr = std::shared_ptr; + +//============================================================================== +/// Factory function type for creating solvers +using LcpSolverFactory = std::function; + +} // namespace math +} // namespace dart + +#endif // DART_MATH_LCP_LCPSOLVER_HPP_ diff --git a/dart/math/lcp/LcpTypes.cpp b/dart/math/lcp/LcpTypes.cpp new file mode 100644 index 0000000000000..fcf0b54fef84b --- /dev/null +++ b/dart/math/lcp/LcpTypes.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011-2025, The DART development contributors + * All rights reserved. + * + * The list of contributors can be found at: + * https://github.com/dartsim/dart/blob/main/LICENSE + * + * This file is provided under the following "BSD-style" License: + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "dart/math/lcp/LcpTypes.hpp" + +namespace dart { +namespace math { + +//============================================================================== +std::string toString(LcpSolverStatus status) +{ + switch (status) { + case LcpSolverStatus::Success: + return "Success"; + case LcpSolverStatus::Failed: + return "Failed"; + case LcpSolverStatus::MaxIterations: + return "MaxIterations"; + case LcpSolverStatus::NumericalError: + return "NumericalError"; + case LcpSolverStatus::InvalidProblem: + return "InvalidProblem"; + case LcpSolverStatus::Degenerate: + return "Degenerate"; + case LcpSolverStatus::NotSolved: + return "NotSolved"; + default: + return "Unknown"; + } +} + +} // namespace math +} // namespace dart diff --git a/dart/math/lcp/LcpTypes.hpp b/dart/math/lcp/LcpTypes.hpp new file mode 100644 index 0000000000000..4727722bbbb98 --- /dev/null +++ b/dart/math/lcp/LcpTypes.hpp @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2011-2025, The DART development contributors + * All rights reserved. + * + * The list of contributors can be found at: + * https://github.com/dartsim/dart/blob/main/LICENSE + * + * This file is provided under the following "BSD-style" License: + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DART_MATH_LCP_LCPTYPES_HPP_ +#define DART_MATH_LCP_LCPTYPES_HPP_ + +#include + +#include + +#include +#include + +namespace dart { +namespace math { + +//============================================================================== +/// Solver exit status codes +enum class LcpSolverStatus +{ + /// Solution found successfully + Success = 0, + + /// Failed to find a solution + Failed = 1, + + /// Maximum iterations reached + MaxIterations = 2, + + /// Numerical issues (NaN, Inf, etc.) + NumericalError = 3, + + /// Invalid problem formulation (e.g., inconsistent dimensions) + InvalidProblem = 4, + + /// Solution is degenerate + Degenerate = 5, + + /// Not yet solved + NotSolved = 6 +}; + +//============================================================================== +/// Convert solver status to string +/// +/// \param[in] status The solver status to convert +/// \return String representation of the status +DART_API std::string toString(LcpSolverStatus status); + +//============================================================================== +/// Solver result structure containing solution status and statistics +struct DART_API LcpResult +{ + /// Exit status + LcpSolverStatus status{LcpSolverStatus::NotSolved}; + + /// Number of iterations performed + int iterations{0}; + + /// Final residual norm + double residual{std::numeric_limits::quiet_NaN()}; + + /// Complementarity error: ||x * (Ax + b)|| + double complementarity{std::numeric_limits::quiet_NaN()}; + + /// Whether the solution was validated + bool validated{false}; + + /// Additional solver-specific information + std::string message; + + /// Default constructor + LcpResult() = default; + + /// Constructor with status + /// + /// \param[in] status_ Initial solver status + explicit LcpResult(LcpSolverStatus status_) : status(status_) {} + + /// Check if solution was successful + /// + /// \return True if status is Success, false otherwise + bool succeeded() const + { + return status == LcpSolverStatus::Success; + } +}; + +//============================================================================== +/// Solver configuration options +struct DART_API LcpOptions +{ + /// Maximum number of iterations (0 = solver default) + int maxIterations{0}; + + /// Absolute tolerance for convergence + double absoluteTolerance{1e-6}; + + /// Relative tolerance for convergence + double relativeTolerance{1e-4}; + + /// Complementarity tolerance + double complementarityTolerance{1e-6}; + + /// Whether to validate the solution after solving + bool validateSolution{true}; + + /// Relaxation parameter for SOR-based methods (1.0 = Gauss-Seidel) + double relaxation{1.0}; + + /// Whether to use warm starting (reuse previous solution) + bool warmStart{false}; + + /// Whether to enable early termination for pivoting methods + bool earlyTermination{false}; + + /// Solver-specific options (reserved for future use) + void* customOptions{nullptr}; + + /// Default constructor with sensible defaults + LcpOptions() = default; + + /// Create options for relaxation-based methods + /// + /// \param[in] relaxation Relaxation parameter + /// \param[in] maxIter Maximum iterations + /// \return Configured LcpOptions + static LcpOptions withRelaxation(double relaxation, int maxIter = 100) + { + LcpOptions opts; + opts.relaxation = relaxation; + opts.maxIterations = maxIter; + return opts; + } + + /// Create options for high accuracy requirements + /// + /// \return Configured LcpOptions with tight tolerances + static LcpOptions highAccuracy() + { + LcpOptions opts; + opts.absoluteTolerance = 1e-10; + opts.relativeTolerance = 1e-8; + opts.maxIterations = 1000; + return opts; + } + + /// Create options for real-time use + /// + /// \return Configured LcpOptions for fast computation + static LcpOptions realTime() + { + LcpOptions opts; + opts.maxIterations = 50; + opts.absoluteTolerance = 1e-4; + opts.validateSolution = false; + return opts; + } +}; + +} // namespace math +} // namespace dart + +#endif // DART_MATH_LCP_LCPTYPES_HPP_ diff --git a/dart/math/lcp/Lemke.cpp b/dart/math/lcp/Lemke.cpp index c4e35bc87c854..332acd02fdb72 100644 --- a/dart/math/lcp/Lemke.cpp +++ b/dart/math/lcp/Lemke.cpp @@ -39,7 +39,7 @@ #include -namespace dart::math::lcp { +namespace dart::math { // double RandDouble(double _low, double _high) { // double temp; @@ -320,4 +320,4 @@ bool validate( return true; } -} // namespace dart::math::lcp +} // namespace dart::math diff --git a/dart/math/lcp/Lemke.hpp b/dart/math/lcp/Lemke.hpp index 5f755a2e65048..37aa6029a7368 100644 --- a/dart/math/lcp/Lemke.hpp +++ b/dart/math/lcp/Lemke.hpp @@ -37,7 +37,7 @@ #include -namespace dart::math::lcp { +namespace dart::math { /// @brief int DART_API Lemke( @@ -49,10 +49,6 @@ bool DART_API validate( const Eigen::VectorXd& _z, const Eigen::VectorXd& _q); -} // namespace dart::math::lcp - -namespace dart::math { -using namespace lcp; } // namespace dart::math #endif // DART_MATH_LCP_LEMKE_HPP_ diff --git a/dart/math/lcp/ODELCPSolver.cpp b/dart/math/lcp/ODELCPSolver.cpp index 034f63869372b..6831131b5fb08 100644 --- a/dart/math/lcp/ODELCPSolver.cpp +++ b/dart/math/lcp/ODELCPSolver.cpp @@ -33,12 +33,12 @@ #include "dart/math/lcp/ODELCPSolver.hpp" #include "dart/common/Macros.hpp" -#include "dart/math/lcp/Dantzig/Lcp.hpp" #include "dart/math/lcp/Lemke.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" #include -namespace dart::math::lcp { +namespace dart::math { //============================================================================== ODELCPSolver::ODELCPSolver() @@ -223,4 +223,4 @@ bool ODELCPSolver::checkIfSolution( return true; } -} // namespace dart::math::lcp +} // namespace dart::math diff --git a/dart/math/lcp/ODELCPSolver.hpp b/dart/math/lcp/ODELCPSolver.hpp index 2d7a4b5348871..30ff3482073c9 100644 --- a/dart/math/lcp/ODELCPSolver.hpp +++ b/dart/math/lcp/ODELCPSolver.hpp @@ -37,7 +37,7 @@ #include -namespace dart::math::lcp { +namespace dart::math { /// @brief class DART_API ODELCPSolver @@ -83,10 +83,6 @@ class DART_API ODELCPSolver const Eigen::VectorXd& _x); }; -} // namespace dart::math::lcp - -namespace dart::math { -using namespace lcp; } // namespace dart::math #endif // DART_MATH_LCP_ODELCPSOLVER_HPP_ diff --git a/dart/math/lcp/Dantzig/Common.hpp b/dart/math/lcp/dantzig/Common.hpp similarity index 92% rename from dart/math/lcp/Dantzig/Common.hpp rename to dart/math/lcp/dantzig/Common.hpp index a34bdcf43c339..8004e8eca3a1b 100644 --- a/dart/math/lcp/Dantzig/Common.hpp +++ b/dart/math/lcp/dantzig/Common.hpp @@ -90,16 +90,7 @@ // misc defines #define ALLOCA dALLOCA16 -/* constants */ - -/* Modern C++ constant for 1/sqrt(2) */ -namespace dart::math::lcp::constants { -template -inline constexpr T sqrt1_2 = static_cast( - 0.707106781186547524400844362104849039284835937688474036588339868999782L); -} // namespace dart::math::lcp::constants - -namespace dart::math::lcp { +namespace dart::math { //============================================================================== // Template Type Traits for Scalar Types @@ -126,7 +117,7 @@ struct ScalarTraits static Scalar reciprocal(Scalar x); /// Reciprocal square root (1/sqrt(x)) - static Scalar recip_sqrt(Scalar x); + static Scalar reciprocalSqrt(Scalar x); /// Sine static Scalar sin(Scalar x); @@ -149,10 +140,35 @@ struct ScalarTraits return std::numeric_limits::infinity(); } + static float sqrt(float x) + { + return std::sqrt(x); + } + static float abs(float x) { return std::fabs(x); } + + static float reciprocal(float x) + { + return 1.0f / x; + } + + static float reciprocalSqrt(float x) + { + return 1.0f / std::sqrt(x); + } + + static float sin(float x) + { + return std::sin(x); + } + + static float cos(float x) + { + return std::cos(x); + } }; /// Specialization for double (64-bit) @@ -169,10 +185,35 @@ struct ScalarTraits return std::numeric_limits::infinity(); } + static double sqrt(double x) + { + return std::sqrt(x); + } + static double abs(double x) { return std::fabs(x); } + + static double reciprocal(double x) + { + return 1.0 / x; + } + + static double reciprocalSqrt(double x) + { + return 1.0 / std::sqrt(x); + } + + static double sin(double x) + { + return std::sin(x); + } + + static double cos(double x) + { + return std::cos(x); + } }; /// Round an integer up to a multiple of 4, except that 0 and 1 are unmodified @@ -290,8 +331,4 @@ inline void Multiply2( } } -} // namespace dart::math::lcp - -namespace dart::math { -using namespace lcp; } // namespace dart::math diff --git a/dart/math/lcp/Dantzig/Lcp-impl.hpp b/dart/math/lcp/dantzig/Lcp-impl.hpp similarity index 99% rename from dart/math/lcp/Dantzig/Lcp-impl.hpp rename to dart/math/lcp/dantzig/Lcp-impl.hpp index ff87dabec36b1..75d7cd587cf87 100644 --- a/dart/math/lcp/Dantzig/Lcp-impl.hpp +++ b/dart/math/lcp/dantzig/Lcp-impl.hpp @@ -57,16 +57,16 @@ #define DART_MATH_LCP_DANTZIG_LCP_IMPL_HPP_ #include "dart/common/Macros.hpp" -#include "dart/math/lcp/Dantzig/Matrix.hpp" -#include "dart/math/lcp/Dantzig/Misc.hpp" -#include "dart/math/lcp/Dantzig/PivotMatrix.hpp" +#include "dart/math/lcp/dantzig/Matrix.hpp" +#include "dart/math/lcp/dantzig/Misc.hpp" +#include "dart/math/lcp/dantzig/PivotMatrix.hpp" #define ROWPTRS // Keep for compatibility (but now uses PivotMatrix internally) #define AROW(i) (m_A[i]) #define NUB_OPTIMIZATIONS -namespace dart::math::lcp { +namespace dart::math { //*************************************************************************** // Template implementations @@ -893,6 +893,6 @@ void LCP::unpermute() #endif // dLCP_FAST -} // namespace dart::math::lcp +} // namespace dart::math #endif // DART_MATH_LCP_DANTZIG_LCP_IMPL_HPP_ diff --git a/dart/math/lcp/Dantzig/Lcp.cpp b/dart/math/lcp/dantzig/Lcp.cpp similarity index 99% rename from dart/math/lcp/Dantzig/Lcp.cpp rename to dart/math/lcp/dantzig/Lcp.cpp index b1929e5c1bec9..253200af09835 100644 --- a/dart/math/lcp/Dantzig/Lcp.cpp +++ b/dart/math/lcp/dantzig/Lcp.cpp @@ -152,11 +152,11 @@ rows/columns and manipulate C. #define NUB_OPTIMIZATIONS -#include "dart/math/lcp/Dantzig/Lcp.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" #include "dart/common/Macros.hpp" -#include "dart/math/lcp/Dantzig/Matrix.hpp" -#include "dart/math/lcp/Dantzig/Misc.hpp" +#include "dart/math/lcp/dantzig/Matrix.hpp" +#include "dart/math/lcp/dantzig/Misc.hpp" #include #include @@ -164,7 +164,7 @@ rows/columns and manipulate C. //*************************************************************************** // code generation parameters -namespace dart::math::lcp { +namespace dart::math { //*************************************************************************** // an optimized Dantzig LCP driver routine for the lo-hi LCP problem. @@ -553,6 +553,6 @@ template DART_API bool SolveLCP( int* findex, bool earlyTermination); -} // namespace dart::math::lcp +} // namespace dart::math // Note: Template implementations are in lcp-impl.hpp (included via lcp.h) diff --git a/dart/math/lcp/Dantzig/Lcp.hpp b/dart/math/lcp/dantzig/Lcp.hpp similarity index 96% rename from dart/math/lcp/Dantzig/Lcp.hpp rename to dart/math/lcp/dantzig/Lcp.hpp index f0dd8839be3d2..1307b2b709446 100644 --- a/dart/math/lcp/Dantzig/Lcp.hpp +++ b/dart/math/lcp/dantzig/Lcp.hpp @@ -56,14 +56,14 @@ #pragma once #include "dart/Export.hpp" -#include "dart/math/lcp/Dantzig/Common.hpp" +#include "dart/math/lcp/dantzig/Common.hpp" #include #include #include -namespace dart::math::lcp { +namespace dart::math { /// Solve the Linear Complementarity Problem using Dantzig's algorithm /// @@ -116,11 +116,7 @@ bool SolveLCP( int* findex, bool earlyTermination = false); -} // namespace dart::math::lcp - -namespace dart::math { -using namespace lcp; } // namespace dart::math // Template implementations for header-only usage -#include "dart/math/lcp/Dantzig/Lcp-impl.hpp" +#include "dart/math/lcp/dantzig/Lcp-impl.hpp" diff --git a/dart/math/lcp/Dantzig/Matrix-impl.hpp b/dart/math/lcp/dantzig/Matrix-impl.hpp similarity index 98% rename from dart/math/lcp/Dantzig/Matrix-impl.hpp rename to dart/math/lcp/dantzig/Matrix-impl.hpp index 285961fd0d493..42599b9365943 100644 --- a/dart/math/lcp/Dantzig/Matrix-impl.hpp +++ b/dart/math/lcp/dantzig/Matrix-impl.hpp @@ -56,9 +56,9 @@ #pragma once #include "dart/common/Macros.hpp" -#include "dart/math/lcp/Dantzig/Common.hpp" +#include "dart/math/lcp/dantzig/Common.hpp" -namespace dart::math::lcp { +namespace dart::math { template void dMultiply0( @@ -238,16 +238,18 @@ void dLDLTAddTL( Scalar* W1 = tmpbuf ? (Scalar*)tmpbuf : (Scalar*)ALLOCA((2 * nskip) * sizeof(Scalar)); Scalar* W2 = W1 + nskip; + const Scalar sqrtHalf + = ScalarTraits::reciprocalSqrt(static_cast(2)); W1[0] = static_cast(0.0); W2[0] = static_cast(0.0); for (int j = 1; j < n; ++j) { - W1[j] = W2[j] = (Scalar)(a[j] * constants::sqrt1_2); + W1[j] = W2[j] = static_cast(a[j] * sqrtHalf); } Scalar W11 - = (Scalar)((static_cast(0.5) * a[0] + 1) * constants::sqrt1_2); + = static_cast((static_cast(0.5) * a[0] + 1) * sqrtHalf); Scalar W21 - = (Scalar)((static_cast(0.5) * a[0] - 1) * constants::sqrt1_2); + = static_cast((static_cast(0.5) * a[0] - 1) * sqrtHalf); Scalar alpha1 = static_cast(1.0); Scalar alpha2 = static_cast(1.0); @@ -1203,8 +1205,4 @@ void dSolveL1T(const Scalar* L, Scalar* b, int n, int nskip) } //============================================================================== -} // namespace dart::math::lcp - -namespace dart::math { -using namespace lcp; } // namespace dart::math diff --git a/dart/math/lcp/Dantzig/Matrix.hpp b/dart/math/lcp/dantzig/Matrix.hpp similarity index 99% rename from dart/math/lcp/Dantzig/Matrix.hpp rename to dart/math/lcp/dantzig/Matrix.hpp index 40cd4694ec3d6..5fd620d4350b0 100644 --- a/dart/math/lcp/Dantzig/Matrix.hpp +++ b/dart/math/lcp/dantzig/Matrix.hpp @@ -56,13 +56,13 @@ #pragma once #include "dart/common/Macros.hpp" -#include "dart/math/lcp/Dantzig/Common.hpp" +#include "dart/math/lcp/dantzig/Common.hpp" #include #include -namespace dart::math::lcp { +namespace dart::math { /// Get the dot product of two nĂ—1 vectors (templated version) /// @param a First vector @@ -600,11 +600,7 @@ inline int IsPositiveDefinite(const Scalar* A, int n, void* tmpbuf = nullptr) return dIsPositiveDefinite(A, n, tmpbuf); } -} // namespace dart::math::lcp - -namespace dart::math { -using namespace lcp; } // namespace dart::math // Include template implementations -#include "dart/math/lcp/Dantzig/Matrix-impl.hpp" +#include "dart/math/lcp/dantzig/Matrix-impl.hpp" diff --git a/dart/math/lcp/Dantzig/Misc.cpp b/dart/math/lcp/dantzig/Misc.cpp similarity index 96% rename from dart/math/lcp/Dantzig/Misc.cpp rename to dart/math/lcp/dantzig/Misc.cpp index 38e22e7694879..530f153fa80e2 100644 --- a/dart/math/lcp/Dantzig/Misc.cpp +++ b/dart/math/lcp/dantzig/Misc.cpp @@ -53,9 +53,9 @@ * LICENSE.TXT and LICENSE-BSD.TXT for more details. */ -#include "dart/math/lcp/Dantzig/Misc.hpp" +#include "dart/math/lcp/dantzig/Misc.hpp" -namespace dart::math::lcp { +namespace dart::math { //============================================================================== // Random number generation @@ -89,4 +89,4 @@ double dRandReal() return static_cast(dRand()) / static_cast(0xffffffff); } -} // namespace dart::math::lcp +} // namespace dart::math diff --git a/dart/math/lcp/Dantzig/Misc.hpp b/dart/math/lcp/dantzig/Misc.hpp similarity index 96% rename from dart/math/lcp/Dantzig/Misc.hpp rename to dart/math/lcp/dantzig/Misc.hpp index 5b25ae446ae9c..c74a7bdd69f97 100644 --- a/dart/math/lcp/Dantzig/Misc.hpp +++ b/dart/math/lcp/dantzig/Misc.hpp @@ -57,9 +57,9 @@ #pragma once -#include "dart/math/lcp/Dantzig/Common.hpp" +#include "dart/math/lcp/dantzig/Common.hpp" -namespace dart::math::lcp { +namespace dart::math { //============================================================================== // Random Number Generation (Used by tests and benchmarks) @@ -87,8 +87,4 @@ inline Scalar RandReal() return static_cast(dRandReal()); } -} // namespace dart::math::lcp - -namespace dart::math { -using namespace lcp; } // namespace dart::math diff --git a/dart/math/lcp/Dantzig/PivotMatrix.hpp b/dart/math/lcp/dantzig/PivotMatrix.hpp similarity index 98% rename from dart/math/lcp/Dantzig/PivotMatrix.hpp rename to dart/math/lcp/dantzig/PivotMatrix.hpp index 45be8cd41a0ea..0e2b69ac4af6d 100644 --- a/dart/math/lcp/Dantzig/PivotMatrix.hpp +++ b/dart/math/lcp/dantzig/PivotMatrix.hpp @@ -33,13 +33,13 @@ #pragma once #include "dart/common/Macros.hpp" -#include "dart/math/lcp/Dantzig/Common.hpp" +#include "dart/math/lcp/dantzig/Common.hpp" #include #include -namespace dart::math::lcp { +namespace dart::math { /// @brief Hybrid pivot matrix: Eigen storage + O(1) row pointer swapping /// @@ -328,8 +328,4 @@ class PivotMatrix using PivotMatrixd = PivotMatrix; using PivotMatrixf = PivotMatrix; -} // namespace dart::math::lcp - -namespace dart::math { -using namespace lcp; } // namespace dart::math diff --git a/dart/math/lcp/pivoting/LemkeSolver.cpp b/dart/math/lcp/pivoting/LemkeSolver.cpp new file mode 100644 index 0000000000000..898e1a8d24541 --- /dev/null +++ b/dart/math/lcp/pivoting/LemkeSolver.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011-2025, The DART development contributors + * All rights reserved. + * + * The list of contributors can be found at: + * https://github.com/dartsim/dart/blob/main/LICENSE + * + * This file is provided under the following "BSD-style" License: + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "dart/math/lcp/pivoting/LemkeSolver.hpp" + +#include "dart/math/lcp/Lemke.hpp" + +namespace dart { +namespace math { + +//============================================================================== +LemkeSolver::LemkeSolver() +{ + // Lemke is an exact solver, no need for iterations or tolerances + mDefaultOptions.maxIterations = 0; // Not applicable + mDefaultOptions.validateSolution = true; // Always validate +} + +//============================================================================== +LcpResult LemkeSolver::solve( + const Eigen::MatrixXd& A, + const Eigen::VectorXd& b, + Eigen::VectorXd& x, + const LcpOptions& options) +{ + LcpResult result; + + // Check problem dimensions + if (A.rows() != A.cols() || A.rows() != b.size()) { + result.status = LcpSolverStatus::InvalidProblem; + result.message = "Matrix dimensions inconsistent"; + return result; + } + + // Call the legacy Lemke solver + const int exitCode = Lemke(A, b, &x); + + // Interpret exit code + result.iterations = 1; // Pivoting methods don't have iterations in same sense + if (exitCode == 0) { + result.status = LcpSolverStatus::Success; + + // Validate solution if requested + if (options.validateSolution) { + const bool isValid = validate(A, x, b); + result.validated = true; + if (!isValid) { + result.status = LcpSolverStatus::NumericalError; + result.message = "Solution validation failed"; + } + } + + // Compute complementarity error + Eigen::VectorXd w = A * x + b; + result.complementarity = (x.array() * w.array()).abs().sum(); + result.residual = (A * x - (-b)).norm(); + } else { + result.status = LcpSolverStatus::Failed; + result.message = "Lemke algorithm failed (no solution found)"; + } + + return result; +} + +//============================================================================== +std::string LemkeSolver::getName() const +{ + return "Lemke"; +} + +//============================================================================== +std::string LemkeSolver::getCategory() const +{ + return "Pivoting"; +} + +} // namespace math +} // namespace dart diff --git a/dart/math/lcp/pivoting/LemkeSolver.hpp b/dart/math/lcp/pivoting/LemkeSolver.hpp new file mode 100644 index 0000000000000..60b06ba289424 --- /dev/null +++ b/dart/math/lcp/pivoting/LemkeSolver.hpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2011-2025, The DART development contributors + * All rights reserved. + * + * The list of contributors can be found at: + * https://github.com/dartsim/dart/blob/main/LICENSE + * + * This file is provided under the following "BSD-style" License: + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DART_MATH_LCP_PIVOTING_LEMKESOLVER_HPP_ +#define DART_MATH_LCP_PIVOTING_LEMKESOLVER_HPP_ + +#include + +#include + +namespace dart { +namespace math { + +//============================================================================== +/// Lemke's complementary pivot algorithm for LCP +/// +/// This solver uses Lemke's algorithm with an artificial variable to solve +/// standard LCPs. It provides exact solutions when they exist. +/// +/// Reference: +/// Lemke, C. E. (1965). "Bimatrix equilibrium points and mathematical +/// programming". Management Science, 11(7), 681-689. +/// +/// Properties: +/// - Time Complexity: O(n^4) worst case +/// - Space Complexity: O(n^2) +/// - Convergence: Exact solution (finite termination) +/// - Matrix Requirements: None (general LCP) +/// +/// Problem formulation: +/// Find z such that: +/// Mz = q + w +/// z >= 0, w >= 0 +/// z^T * w = 0 +class DART_API LemkeSolver : public LcpSolver +{ +public: + /// Constructor + LemkeSolver(); + + /// Destructor + ~LemkeSolver() override = default; + + // Documentation inherited + LcpResult solve( + const Eigen::MatrixXd& A, + const Eigen::VectorXd& b, + Eigen::VectorXd& x, + const LcpOptions& options) override; + + // Documentation inherited + std::string getName() const override; + + // Documentation inherited + std::string getCategory() const override; +}; + +} // namespace math +} // namespace dart + +#endif // DART_MATH_LCP_PIVOTING_LEMKESOLVER_HPP_ diff --git a/dart8/io/serializer.hpp b/dart8/io/serializer.hpp index 84a938a38c578..198e99724ca3f 100644 --- a/dart8/io/serializer.hpp +++ b/dart8/io/serializer.hpp @@ -227,8 +227,8 @@ class TypedComponentSerializer : public ComponentSerializer { ComponentT component; loadComponent(in, component); + if constexpr (std::is_empty_v) { - // Tag components in EnTT must be emplaced without constructor args registry.emplace(entity); } else { registry.emplace(entity, std::move(component)); diff --git a/examples/human_joint_limits/HumanArmJointLimitConstraint.cpp b/examples/human_joint_limits/HumanArmJointLimitConstraint.cpp index 0ef93b64166d0..0dea843308e19 100644 --- a/examples/human_joint_limits/HumanArmJointLimitConstraint.cpp +++ b/examples/human_joint_limits/HumanArmJointLimitConstraint.cpp @@ -40,7 +40,7 @@ #include #include -#include +#include #include #include diff --git a/examples/human_joint_limits/HumanLegJointLimitConstraint.cpp b/examples/human_joint_limits/HumanLegJointLimitConstraint.cpp index 160e8cf72a719..9f84c999048a3 100644 --- a/examples/human_joint_limits/HumanLegJointLimitConstraint.cpp +++ b/examples/human_joint_limits/HumanLegJointLimitConstraint.cpp @@ -40,7 +40,7 @@ #include #include -#include +#include #include #include diff --git a/tests/benchmark/lcpsolver/bm_lcpsolver.cpp b/tests/benchmark/lcpsolver/bm_lcpsolver.cpp index ba25510846a4b..141d2c2dc10d5 100644 --- a/tests/benchmark/lcpsolver/bm_lcpsolver.cpp +++ b/tests/benchmark/lcpsolver/bm_lcpsolver.cpp @@ -8,7 +8,7 @@ * Benchmark comparing Dantzig LCP solver vs ODE baseline */ -#include "dart/math/lcp/Dantzig/Lcp.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" #include "tests/baseline/odelcpsolver/lcp.h" #include "tests/common/lcpsolver/LCPTestProblems.hpp" @@ -88,7 +88,7 @@ static void BM_Dantzig_F64_Solver( for (auto _ : state) { data.reset(problem); - // Solve LCP using Dantzig solver (from dart/math/lcp/Dantzig/) + // Solve LCP using Dantzig solver (from dart/math/lcp/dantzig/) bool success = dart::math::SolveLCP( data.n, data.A.data(), diff --git a/tests/benchmark/lcpsolver/bm_matrix_multiply.cpp b/tests/benchmark/lcpsolver/bm_matrix_multiply.cpp index 256191289a537..7d4ac3b49b591 100644 --- a/tests/benchmark/lcpsolver/bm_matrix_multiply.cpp +++ b/tests/benchmark/lcpsolver/bm_matrix_multiply.cpp @@ -30,7 +30,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include +#include #include #include diff --git a/tests/unit/lcpsolver/test_DantzigVsODE.cpp b/tests/unit/lcpsolver/test_DantzigVsODE.cpp index 7a380b12407c1..de0d559a7dae4 100644 --- a/tests/unit/lcpsolver/test_DantzigVsODE.cpp +++ b/tests/unit/lcpsolver/test_DantzigVsODE.cpp @@ -30,8 +30,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "dart/math/lcp/Dantzig/Common.hpp" -#include "dart/math/lcp/Dantzig/Lcp.hpp" +#include "dart/math/lcp/dantzig/Common.hpp" +#include "dart/math/lcp/dantzig/Lcp.hpp" // Undefine assertion macros from dantzig to avoid conflicts with baseline #undef dIASSERT @@ -53,7 +53,7 @@ // Types from both implementations using dReal = double; // Compatibility alias for tests - // dart/math/lcp/Dantzig/) + // dart/math/lcp/dantzig/) // Forward declare the baseline function namespace dart { @@ -173,7 +173,7 @@ void testDantzigVsODE(dart::test::LCPProblem problem) nullptr, false); - // Solve with Dantzig solver (from dart/math/lcp/Dantzig/) + // Solve with Dantzig solver (from dart/math/lcp/dantzig/) bool success_dantzig = dart::math::SolveLCP( n, A_dantzig.data(), diff --git a/tests/unit/lcpsolver/test_PivotMatrix.cpp b/tests/unit/lcpsolver/test_PivotMatrix.cpp index c882080ba9099..274dcd7f558e8 100644 --- a/tests/unit/lcpsolver/test_PivotMatrix.cpp +++ b/tests/unit/lcpsolver/test_PivotMatrix.cpp @@ -3,7 +3,7 @@ * All rights reserved. */ -#include "dart/math/lcp/Dantzig/PivotMatrix.hpp" +#include "dart/math/lcp/dantzig/PivotMatrix.hpp" #include