Skip to content

Commit

Permalink
Merge pull request #22 from olivier-roussel/allow-external-qpOASES-2
Browse files Browse the repository at this point in the history
[config] Allow external qpOASES dependency
  • Loading branch information
olivier-roussel authored Feb 3, 2025
2 parents c338ef2 + 1c23d01 commit 653a922
Show file tree
Hide file tree
Showing 21 changed files with 381 additions and 124 deletions.
30 changes: 26 additions & 4 deletions .github/workflows/ci-conda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ on:

jobs:
build-with-conda-and-test:
name: "[conda:${{ matrix.os }}:py${{ matrix.python_version }}]"
name: "[conda:${{ matrix.os }}:py${{ matrix.python_version }}:${{ matrix.qp_solver }}]"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, macos-13, macos-14, windows-2022]
python_version: ["3.13"]
build_type: ["Release"]
qp_solver: ["qpOases", "proxQP"]

steps:
- name: Install miniconda [Linux & macOS & Windows]
Expand Down Expand Up @@ -57,7 +58,28 @@ jobs:
- name: Install dependencies [Conda]
shell: bash -l {0}
run: |
conda install eigen libboost-headers pybind11 cxxopts
conda install eigen libboost-headers pybind11 cxxopts
- name: Install QP solver dependencies [Conda / proxQP]
if: contains(matrix.qp_solver, 'proxQP')
shell: bash -l {0}
run: |
conda install proxsuite
echo "CMAKE_OPTS_QPSOLVER=-DSOFTROBOTSINVERSE_ENABLE_PROXQP=ON -DSOFTROBOTSINVERSE_ENABLE_QPOASES=OFF" >> "$GITHUB_ENV"
- name: Install QP solver dependencies [Conda / qpOases & not osx-arm64]
if: contains(matrix.qp_solver, 'qpOases') && !contains(matrix.os, 'macos-14')
shell: bash -l {0}
run: |
conda install qpoases
echo "CMAKE_OPTS_QPSOLVER=-DSOFTROBOTSINVERSE_ENABLE_PROXQP=OFF -DSOFTROBOTSINVERSE_ENABLE_QPOASES=ON" >> "$GITHUB_ENV"
# Use embedded qpOases version as its conda package for python>3.10 under osx-arm64 platform is not supported anymore
- name: Install QP solver dependencies [Conda / qpOases & osx-arm64]
if: contains(matrix.qp_solver, 'qpOases') && contains(matrix.os, 'macos-14')
shell: bash -l {0}
run: |
echo "CMAKE_OPTS_QPSOLVER=-DSOFTROBOTSINVERSE_ENABLE_PROXQP=OFF -DSOFTROBOTSINVERSE_ENABLE_QPOASES=ON" >> "$GITHUB_ENV"
- name: Print environment [Conda]
shell: bash -l {0}
Expand All @@ -72,7 +94,7 @@ jobs:
run: |
mkdir build
cd build
cmake .. -GNinja \
cmake .. -GNinja $CMAKE_OPTS_QPSOLVER \
-DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} \
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
-DPython_EXECUTABLE:PATH=${CONDA_PREFIX}/bin/python \
Expand All @@ -84,7 +106,7 @@ jobs:
run: |
mkdir build
cd build
cmake .. -G"Visual Studio 17 2022" -T "v143" \
cmake .. -G"Visual Studio 17 2022" -T "v143" $CMAKE_OPTS_QPSOLVER \
-DCMAKE_GENERATOR_PLATFORM=x64 \
-DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} \
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
Expand Down
58 changes: 44 additions & 14 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ set(HEADER_FILES
${SRC_DIR}/component/solver/modules/NLCPSolver.h
${SRC_DIR}/component/solver/modules/QPInverseProblem.h
${SRC_DIR}/component/solver/modules/QPInverseProblemImpl.h
${SRC_DIR}/component/solver/modules/QPInverseProblemQPOases.h
${SRC_DIR}/component/solver/modules/QPMechanicalAccumulateConstraint.h
${SRC_DIR}/component/solver/modules/QPMechanicalSetConstraint.h
)
Expand Down Expand Up @@ -119,11 +118,9 @@ set(SOURCE_FILES
${SRC_DIR}/component/solver/QPInverseProblemSolver.cpp
${SRC_DIR}/component/solver/modules/ContactHandler.cpp
${SRC_DIR}/component/solver/modules/ConstraintHandler.cpp
${SRC_DIR}/component/solver/modules/LCPQPSolver.cpp
${SRC_DIR}/component/solver/modules/NLCPSolver.cpp
${SRC_DIR}/component/solver/modules/QPInverseProblem.cpp
${SRC_DIR}/component/solver/modules/QPInverseProblemImpl.cpp
${SRC_DIR}/component/solver/modules/QPInverseProblemQPOases.cpp
${SRC_DIR}/component/solver/modules/QPMechanicalAccumulateConstraint.cpp
${SRC_DIR}/component/solver/modules/QPMechanicalSetConstraint.cpp
)
Expand All @@ -141,24 +138,33 @@ endif()
set(DOC_FILES README.md)
file(GLOB_RECURSE EXAMPLE_FILES examples "*.pyscn" "*.py" "*.md" "*.psl" "*.pslx" "*.scn" "*.xml")

set(OASES_LIBRARY_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/extlibs/qpOASES-3.2.0/")
add_subdirectory(${OASES_LIBRARY_DIRECTORY} extlibs/libqpOASES)
find_package(libqpOASES REQUIRED)
message("libqpOASES_INCLUDE_DIRS = ${libqpOASES_INCLUDE_DIRS}")
include_directories(${libqpOASES_INCLUDE_DIRS})
set(QPOASES_INCLUDE_DIR ${libqpOASES_INCLUDE_DIRS} CACHE INTERNAL "")
sofa_install_libraries(PATHS ${libqpOASES_LIBRARY})

option(SOFTROBOTSINVERSE_ENABLE_PROXQP "Build proxQP wrapper for inverse problems" OFF)
if(SOFTROBOTSINVERSE_ENABLE_PROXQP)
find_package(proxsuite REQUIRED)
message("Sofa.SoftRobots.Inverse: proxsuite FOUND. Will build with proxsuite support.")
option(SOFTROBOTSINVERSE_ENABLE_QPOASES "Build qpOASES wrapper for inverse problems" ON)

if(NOT SOFTROBOTSINVERSE_ENABLE_PROXQP AND NOT SOFTROBOTSINVERSE_ENABLE_QPOASES)
message(FATAL_ERROR "Both proxQP and qpOASES solvers are disabled. Please enable at least one solver.")
endif()

if(SOFTROBOTSINVERSE_ENABLE_PROXQP)
list(APPEND HEADER_FILES
${SRC_DIR}/component/solver/modules/QPInverseProblemProxQP.h
${SRC_DIR}/component/solver/modules/LCPQPSolverProxQP.h
)
list(APPEND SOURCE_FILES
${SRC_DIR}/component/solver/modules/QPInverseProblemProxQP.cpp
${SRC_DIR}/component/solver/modules/LCPQPSolverProxQP.cpp
)
endif()

if(SOFTROBOTSINVERSE_ENABLE_QPOASES)
list(APPEND HEADER_FILES
${SRC_DIR}/component/solver/modules/QPInverseProblemQPOases.h
${SRC_DIR}/component/solver/modules/LCPQPSolverQPOases.h
)
list(APPEND SOURCE_FILES
${SRC_DIR}/component/solver/modules/QPInverseProblemQPOases.cpp
${SRC_DIR}/component/solver/modules/LCPQPSolverQPOases.cpp
)
endif()

Expand All @@ -169,7 +175,11 @@ else()
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${DOC_FILES} ${EXAMPLE_FILES} "${SRC_DIR}/component/config.h.in")
endif()


if(SOFTROBOTSINVERSE_ENABLE_PROXQP)
find_package(proxsuite REQUIRED)
message("Sofa.SoftRobots.Inverse: proxsuite FOUND. Will build with proxsuite support.")

target_link_libraries(${PROJECT_NAME} PUBLIC proxsuite::proxsuite)
# XXX proxsuite vectorization support via SIMDE and activated by the compilation options '-march=native' or `-mavx2 -mavx512f`
# This will not be available if proxsuite has been fetched
Expand All @@ -178,11 +188,31 @@ if(SOFTROBOTSINVERSE_ENABLE_PROXQP)
target_compile_definitions(${PROJECT_NAME} PUBLIC SOFTROBOTSINVERSE_ENABLE_PROXQP)
endif()

if(SOFTROBOTSINVERSE_ENABLE_QPOASES)
find_package(qpOASES QUIET)

if(qpOASES_FOUND)
message("Sofa.SoftRobots.Inverse: external qpOASES FOUND. Will build with qpOASES support.")
include_directories(${qpOASES_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} PUBLIC ${qpOASES_LIBRARIES})
set(QPOASES_INCLUDE_DIR ${qpOASES_INCLUDE_DIRS} CACHE INTERNAL "")
else()
message("External package qpOASES not found, using embedded version for qpOASES support")
set(OASES_LIBRARY_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/extlibs/qpOASES-3.2.0/")
add_subdirectory(${OASES_LIBRARY_DIRECTORY} extlibs/libqpOASES)
find_package(libqpOASES REQUIRED)
include_directories(${libqpOASES_INCLUDE_DIRS})
set(QPOASES_INCLUDE_DIR ${libqpOASES_INCLUDE_DIRS} CACHE INTERNAL "")
sofa_install_libraries(PATHS ${libqpOASES_LIBRARY})
target_link_libraries(${PROJECT_NAME} PUBLIC ${libqpOASES_LIBRARY})
endif()
target_compile_definitions(${PROJECT_NAME} PUBLIC SOFTROBOTSINVERSE_ENABLE_QPOASES)
endif()

target_link_libraries(${PROJECT_NAME} PUBLIC
SoftRobots
Sofa.Component.Constraint.Lagrangian.Solver
Sofa.Component.Collision.Response.Contact)
target_link_libraries(${PROJECT_NAME} PUBLIC ${libqpOASES_LIBRARY})

sofa_find_package(Sofa.Component.SolidMechanics.FEM.Elastic)
target_link_libraries(${PROJECT_NAME} PUBLIC Sofa.Component.SolidMechanics.FEM.Elastic)
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
23 changes: 23 additions & 0 deletions cmake/Modules/FindqpOASES.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Find the qpOASES includes and libraries.
# The following variables are set if qpOASES is found. If qpOASES is not
# found, qpOASES_FOUND is set to false.
# qpOASES_FOUND - True when the qpOASES include directory is found.
# qpOASES_INCLUDE_DIRS - the path to where the qpOASES include files are.
# qpOASES_LIBRARIES - The libraries to link against qpOASES

include(FindPackageHandleStandardArgs)

find_path(qpOASES_INCLUDE_DIR
NAMES qpOASES.hpp
PATH_SUFFIXES include
)

find_library(qpOASES_LIBRARY
NAMES qpOASES
PATH_SUFFIXES lib
)

set(qpOASES_INCLUDE_DIRS ${qpOASES_INCLUDE_DIR})
set(qpOASES_LIBRARIES ${qpOASES_LIBRARY})

find_package_handle_standard_args(qpOASES DEFAULT_MSG qpOASES_LIBRARIES qpOASES_INCLUDE_DIRS)
62 changes: 0 additions & 62 deletions cmake/modules/FindOASES.cmake

This file was deleted.

17 changes: 15 additions & 2 deletions src/SoftRobots.Inverse/component/solver/QPInverseProblemSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@
#include <SoftRobots.Inverse/component/solver/QPInverseProblemSolver.h>
#include <SoftRobots.Inverse/component/solver/modules/QPMechanicalSetConstraint.h>
#include <SoftRobots.Inverse/component/solver/modules/QPMechanicalAccumulateConstraint.h>

#ifdef SOFTROBOTSINVERSE_ENABLE_QPOASES
#include <SoftRobots.Inverse/component/solver/modules/QPInverseProblemQPOases.h>
#endif

#ifdef SOFTROBOTSINVERSE_ENABLE_PROXQP
#include <SoftRobots.Inverse/component/solver/modules/QPInverseProblemProxQP.h>
Expand Down Expand Up @@ -161,7 +164,12 @@ QPInverseProblemSolver::QPInverseProblemSolver()
, m_CP3(nullptr)
{
sofa::helper::OptionsGroup qpSolvers{"qpOASES" , "proxQP"};
#if defined SOFTROBOTSINVERSE_ENABLE_PROXQP && !defined SOFTROBOTSINVERSE_ENABLE_QPOASES
qpSolvers.setSelectedItem(QPSolverImpl::PROXQP);
#else
qpSolvers.setSelectedItem(QPSolverImpl::QPOASES);
#endif

d_qpSolver.setValue(qpSolvers);

d_graph.setWidget("graph");
Expand All @@ -181,19 +189,24 @@ void QPInverseProblemSolver::createProblems()
{
#ifdef SOFTROBOTSINVERSE_ENABLE_PROXQP
case QPSolverImpl::PROXQP :
// TODO conditionnal compilation w.r.t. optionnal proxQP dependency
msg_info() << "Using proxQP solver";
m_CP1 = new module::QPInverseProblemProxQP();
m_CP2 = new module::QPInverseProblemProxQP();
m_CP3 = new module::QPInverseProblemProxQP();
break;
#endif
default : // QPSolverImpl::QPOASES
#ifdef SOFTROBOTSINVERSE_ENABLE_QPOASES
case QPSolverImpl::QPOASES :
msg_info() << "Using qpOASES solver";
m_CP1 = new module::QPInverseProblemQPOases();
m_CP2 = new module::QPInverseProblemQPOases();
m_CP3 = new module::QPInverseProblemQPOases();
break;
#endif
default :
msg_error() << "Unkown specified solved: " << d_qpSolver.getValue();
sofa::core::objectmodel::BaseObject::d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid);
break;
}


Expand Down
11 changes: 2 additions & 9 deletions src/SoftRobots.Inverse/component/solver/modules/LCPQPSolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,17 @@
******************************************************************************/
#pragma once

#include <sofa/type/vector.h>

// LCP solver using qpOASES QP solver
// QP formulation for solving a LCP with a symmetric matrix M.

namespace softrobotsinverse::solver::module {

using sofa::type::vector;

class LCPQPSolver
{

public:
virtual ~LCPQPSolver() = default;

LCPQPSolver(){}
~LCPQPSolver(){}

void solve(int dim, double*q, double**M, double*res);
virtual void solve(int dim, double*q, double**M, double*res) = 0;
};

} // namespace
Expand Down
Loading

0 comments on commit 653a922

Please sign in to comment.