diff --git a/CMakeLists.txt b/CMakeLists.txt
index 95692171b86e85ab125b39451f7f7849de3920c3..ee1f86f5a773b12a1e27181afb6bd3173d7ba60e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,7 @@
 cmake_minimum_required(VERSION 2.6)
 INCLUDE(cmake/base.cmake)
 INCLUDE(cmake/cpack.cmake)
-
+INCLUDE(cmake2/FindqpOASES.cmake)
 
 SET(PROJECT_NAME robust-equilibrium-lib)
 SET(PROJECT_DESCRIPTION
@@ -36,6 +36,7 @@ SET(${PROJECT_NAME}_HEADERS
     include/robust-equilibrium-lib/solver_LP_qpoases.hh
     include/robust-equilibrium-lib/solver_LP_clp.hh
     include/robust-equilibrium-lib/static_equilibrium.hh
+    include/robust-equilibrium-lib/stop-watch.hh
   )
 
 find_package(Eigen3)
@@ -48,6 +49,7 @@ endif()
 
 find_package(CDD REQUIRED)
 find_package(CLP REQUIRED)
+SEARCH_FOR_QPOASES()
 
 add_subdirectory (src)
 add_subdirectory (test)
diff --git a/cmake2/FindqpOASES.cmake b/cmake2/FindqpOASES.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..0f349c647571c52100c0f840c4a1faa54b82f1b7
--- /dev/null
+++ b/cmake2/FindqpOASES.cmake
@@ -0,0 +1,53 @@
+#.rst:
+# FindqpOASES
+# -----------
+#
+# Try to find the qpOASES library.
+# Once done this will define the following variables::
+#
+#  qpOASES_FOUND         - System has qpOASES
+#  qpOASES_INCLUDE_DIR   - qpOASES include directory
+#  qpOASES_LIBRARY       - qpOASES libraries
+#
+# qpOASES does not have an "install" step, and the includes are in the source
+# tree, while the libraries are in the build tree.
+# Therefore the environment and cmake variables `qpOASES_SOURCE_DIR` and
+# `qpOASES_BINARY_DIR` will be used to locate the includes and libraries.
+
+#=============================================================================
+# Copyright 2014 iCub Facility, Istituto Italiano di Tecnologia
+#   Authors: Daniele E. Domenichelli <daniele.domenichelli@iit.it>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of YCM, substitute the full
+#  License text for the above reference.)
+MACRO(SEARCH_FOR_QPOASES)
+
+include(FindPackageHandleStandardArgs)
+
+find_path(qpOASES_INCLUDEDIR
+          NAMES qpOASES.hpp
+          HINTS "${qpOASES_SOURCE_DIR}"
+                ENV qpOASES_SOURCE_DIR
+          PATH_SUFFIXES include)
+find_library(qpOASES_LIB
+             NAMES qpOASES
+             HINTS "${qpOASES_BINARY_DIR}"
+                   ENV qpOASES_BINARY_DIR
+             PATH_SUFFIXES lib
+                           libs)
+
+set(qpOASES_INCLUDE_DIR ${qpOASES_INCLUDEDIR})
+set(qpOASES_LIBRARY ${qpOASES_LIB})
+
+find_package_handle_standard_args(qpOASES DEFAULT_MSG qpOASES_LIBRARY
+                                                      qpOASES_INCLUDE_DIR)
+set(qpOASES_FOUND ${QPOASES_FOUND})
+
+ENDMACRO(SEARCH_FOR_QPOASES)
diff --git a/include/robust-equilibrium-lib/Stdafx.hh b/include/robust-equilibrium-lib/Stdafx.hh
new file mode 100644
index 0000000000000000000000000000000000000000..8e7b109b8e1346c59dd69a2a7bc3f3d14afbfb7d
--- /dev/null
+++ b/include/robust-equilibrium-lib/Stdafx.hh
@@ -0,0 +1,32 @@
+/*
+Copyright (c) 2010-2013 Tommaso Urli
+
+Tommaso Urli    tommaso.urli@uniud.it   University of Udine
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+#pragma once
+
+#include <iostream>
+#include <map>
+#include <ctime>
+#include <sstream>
diff --git a/include/robust-equilibrium-lib/logger.hh b/include/robust-equilibrium-lib/logger.hh
index 98180c88a7b1ad86270d5044e103c052e6865443..565d9c3c088a5a500d29569ade9ffcd2b61aab78 100644
--- a/include/robust-equilibrium-lib/logger.hh
+++ b/include/robust-equilibrium-lib/logger.hh
@@ -12,6 +12,7 @@
 
 #include <robust-equilibrium-lib/config.hh>
 #include <sstream>
+#include <Eigen/Dense>
 #include <map>
 #include <initializer_list>
 #include "boost/assign.hpp"
@@ -100,6 +101,16 @@ namespace robust_equilibrium
     return ss.str();
   }
 
+  template<typename T, int n>
+  std::string toString(const Eigen::MatrixBase<T>& v, const std::string separator=", ")
+  {
+    if(v.rows()>v.cols())
+      return toString(v.transpose(), separator);
+    std::stringstream ss;
+    ss<<v;
+    return ss.str();
+  }
+
   enum ROBUST_EQUILIBRIUM_DLLAPI LoggerVerbosity
   {
     VERBOSITY_ALL,
diff --git a/include/robust-equilibrium-lib/solver_LP_abstract.hh b/include/robust-equilibrium-lib/solver_LP_abstract.hh
index 9f03bbe45a10f93fd3f1ebaeb671a2184df6fe97..f807b4c4d5049235caa14f6e4673686e53660d14 100644
--- a/include/robust-equilibrium-lib/solver_LP_abstract.hh
+++ b/include/robust-equilibrium-lib/solver_LP_abstract.hh
@@ -52,6 +52,10 @@ public:
   /** Get the objective value of the last solved problem. */
   virtual double getObjectiveValue() = 0;
 
+  virtual void getDualSolution(Ref_vectorX res) = 0;
+
+//  virtual void getDualColumnSolution(Ref_vectorX res) = 0;
+
   /** Get the current maximum number of iterations performed
    *  by the solver.
    */
diff --git a/include/robust-equilibrium-lib/solver_LP_clp.hh b/include/robust-equilibrium-lib/solver_LP_clp.hh
index 2478a43c180a1db6ae7a4132982acc7082d8cb7a..cc39625294420276314dffadbd501f87a2c6131d 100644
--- a/include/robust-equilibrium-lib/solver_LP_clp.hh
+++ b/include/robust-equilibrium-lib/solver_LP_clp.hh
@@ -38,6 +38,10 @@ public:
   /** Get the objective value of the last solved problem. */
   double getObjectiveValue();
 
+  void getDualSolution(Ref_vectorX res);
+
+//  void getDualColumnSolution(Ref_vectorX res);
+
   /** Get the current maximum number of iterations performed
    *  by the solver.
    */
diff --git a/include/robust-equilibrium-lib/solver_LP_qpoases.hh b/include/robust-equilibrium-lib/solver_LP_qpoases.hh
index ed3b1456d385423d3b32b4006b41de87c0547acb..70c99854b0e2a03f782ebb8194558cb7ff480066 100644
--- a/include/robust-equilibrium-lib/solver_LP_qpoases.hh
+++ b/include/robust-equilibrium-lib/solver_LP_qpoases.hh
@@ -2,3 +2,68 @@
  * Copyright 2015, LAAS-CNRS
  * Author: Andrea Del Prete
  */
+
+#ifndef ROBUST_EQUILIBRIUM_LIB_SOLVER_QPOASES_HH
+#define ROBUST_EQUILIBRIUM_LIB_SOLVER_QPOASES_HH
+
+#include <robust-equilibrium-lib/config.hh>
+#include <robust-equilibrium-lib/util.hh>
+#include <robust-equilibrium-lib/solver_LP_abstract.hh>
+#include <qpOASES.hpp>
+
+namespace robust_equilibrium
+{
+
+class ROBUST_EQUILIBRIUM_DLLAPI Solver_LP_qpoases: public Solver_LP_abstract
+{
+private:
+  qpOASES::Options    m_options;  // solver options
+  qpOASES::SQProblem  m_solver;   // qpoases solver
+
+  MatrixXX              m_H;              // Hessian matrix
+  bool                  m_init_succeeded; // true if solver has been successfully initialized
+  qpOASES::returnValue  m_status;         // status code returned by the solver
+  int                   m_maxIter;        // max number of iterations
+  double                m_maxTime;        // max time to solve the LP [s]
+
+public:
+
+  Solver_LP_qpoases();
+
+  /** Solve the linear program
+   *  minimize    c' x
+   *  subject to  Alb <= A x <= Aub
+   *              lb <= x <= ub
+   */
+  LP_status solve(Cref_vectorX c, Cref_vectorX lb, Cref_vectorX ub,
+                  Cref_matrixXX A, Cref_vectorX Alb, Cref_vectorX Aub,
+                  Ref_vectorX sol);
+
+  /** Get the status of the solver. */
+  LP_status getStatus();
+
+  /** Get the objective value of the last solved problem. */
+  double getObjectiveValue();
+
+  void getDualSolution(Ref_vectorX res);
+
+//  void getDualColumnSolution(Ref_vectorX res);
+
+  /** Get the current maximum number of iterations performed
+   *  by the solver.
+   */
+  unsigned int getMaximumIterations();
+
+  /** Set the current maximum number of iterations performed
+   *  by the solver.
+   */
+  bool setMaximumIterations(unsigned int maxIter);
+
+  /** Set the maximum time allowed to solve a problem. */
+  bool setMaximumTime(double seconds);
+
+};
+
+} // end namespace robust_equilibrium
+
+#endif //ROBUST_EQUILIBRIUM_LIB_SOLVER_QPOASES_HH
diff --git a/include/robust-equilibrium-lib/static_equilibrium.hh b/include/robust-equilibrium-lib/static_equilibrium.hh
index 8c1e94ea8d0253d3e05dfba0693a5d5ec0632c94..e3825a1cf0bb96a65d7c4f32bfc4734447fb85f5 100644
--- a/include/robust-equilibrium-lib/static_equilibrium.hh
+++ b/include/robust-equilibrium-lib/static_equilibrium.hh
@@ -17,6 +17,8 @@ namespace robust_equilibrium
 enum ROBUST_EQUILIBRIUM_DLLAPI StaticEquilibriumAlgorithm
 {
   STATIC_EQUILIBRIUM_ALGORITHM_LP,
+  STATIC_EQUILIBRIUM_ALGORITHM_LP2,
+  STATIC_EQUILIBRIUM_ALGORITHM_DLP,
   STATIC_EQUILIBRIUM_ALGORITHM_PP,
   STATIC_EQUILIBRIUM_ALGORITHM_IP,
   STATIC_EQUILIBRIUM_ALGORITHM_DIP
diff --git a/include/robust-equilibrium-lib/stop-watch.hh b/include/robust-equilibrium-lib/stop-watch.hh
new file mode 100644
index 0000000000000000000000000000000000000000..b86cfeb06ec377f8dfd5967a1c50b4082c852c2b
--- /dev/null
+++ b/include/robust-equilibrium-lib/stop-watch.hh
@@ -0,0 +1,267 @@
+/*
+Copyright (c) 2010-2013 Tommaso Urli
+
+Tommaso Urli    tommaso.urli@uniud.it   University of Udine
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+
+#ifndef WBR_STOPWATCH_H
+#define WBR_STOPWATCH_H
+
+#include "robust-equilibrium-lib/Stdafx.hh"
+
+#ifndef WIN32
+	/* The classes below are exported */
+	#pragma GCC visibility push(default)
+#endif
+
+// Generic stopwatch exception class
+struct StopwatchException 
+{
+public:
+  StopwatchException(std::string error) : error(error) { }
+  std::string error;
+};
+
+
+enum StopwatchMode 
+{
+  NONE	    = 0,  // Clock is not initialized
+  CPU_TIME  = 1,  // Clock calculates time ranges using ctime and CLOCKS_PER_SEC
+  REAL_TIME = 2   // Clock calculates time by asking the operating system how
+                  // much real time passed
+};
+
+/** 
+    @brief A class representing a stopwatch.
+    
+    @code
+    Stopwatch swatch();
+    @endcode
+    
+    The Stopwatch class can be used to measure execution time of code,
+    algorithms, etc., // TODO: he Stopwatch can be initialized in two
+    time-taking modes, CPU time and real time:
+	
+    @code
+    swatch.set_mode(REAL_TIME);
+    @endcode
+    
+    CPU time is the time spent by the processor on a certain piece of code,
+    while real time is the real amount of time taken by a certain piece of
+    code to execute (i.e. in general if you are doing hard work such as
+    image or video editing on a different process the measured time will
+    probably increase).
+    
+    How does it work? Basically, one wraps the code to be measured with the
+    following method calls:
+	
+    @code
+    swatch.start("My astounding algorithm");
+    // Hic est code
+    swatch.stop("My astounding algorithm");
+    @endcode
+    
+    A string representing the code ID is provided so that nested portions of
+    code can be profiled separately:
+	
+    @code
+    swatch.start("My astounding algorithm");
+    
+    swatch.start("My astounding algorithm - Super smart init");
+    // Initialization
+    swatch.stop("My astounding algorithm - Super smart init");
+    
+    swatch.start("My astounding algorithm - Main loop");
+    // Loop
+    swatch.stop("My astounding algorithm - Main loop");
+    
+    swatch.stop("My astounding algorithm");
+    @endcode
+    
+    Note: ID strings can be whatever you like, in the previous example I have
+    used "My astounding algorithm - *" only to enforce the fact that the
+    measured code portions are part of My astounding algorithm, but there's no
+    connection between the three measurements.
+		
+    If the code for a certain task is scattered through different files or
+    portions of the same file one can use the start-pause-stop method:
+	
+    @code
+    swatch.start("Setup");
+    // First part of setup
+    swatch.pause("Setup");
+    
+    swatch.start("Main logic");
+    // Main logic
+    swatch.stop("Main logic");
+    
+    swatch.start("Setup");
+    // Cleanup (part of the setup)
+    swatch.stop("Setup");
+    @endcode
+    
+    Finally, to report the results of the measurements just run:
+    
+    @code
+    swatch.report("Code ID");
+    @endcode
+    
+    Thou can also provide an additional std::ostream& parameter to report() to
+    redirect the logging on a different output. Also, you can use the
+    get_total/min/max/average_time() methods to get the individual numeric data,
+    without all the details of the logging. You can also extend Stopwatch to
+    implement your own logging syntax.
+		
+    To report all the measurements:
+    
+    @code
+    swatch.report_all();
+    @endcode
+    
+    Same as above, you can redirect the output by providing a std::ostream&
+    parameter.
+
+*/
+class Stopwatch {
+public:
+	
+  /** Constructor */
+  Stopwatch(StopwatchMode _mode=NONE);
+  
+  /** Destructor */
+  ~Stopwatch();
+  
+  /** Tells if a performance with a certain ID exists */
+  bool performance_exists(std::string perf_name);
+  
+  /** Initialize stopwatch to use a certain time taking mode */
+  void set_mode(StopwatchMode mode);
+  
+  /** Start the stopwatch related to a certain piece of code */
+  void start(std::string perf_name);
+  
+  /** Stops the stopwatch related to a certain piece of code */
+  void stop(std::string perf_name);
+  
+  /** Stops the stopwatch related to a certain piece of code */
+  void pause(std::string perf_name);
+  
+  /** Reset a certain performance record */
+  void reset(std::string perf_name);
+  
+  /** Resets all the performance records */
+  void reset_all();
+  
+  /** Dump the data of a certain performance record */
+  void report(std::string perf_name, int precision=2, 
+              std::ostream& output = std::cout);
+  
+  /** Dump the data of all the performance records */
+  void report_all(int precision=2, std::ostream& output = std::cout);
+  
+  /** Returns total execution time of a certain performance */
+  long double get_total_time(std::string perf_name);
+  
+  /** Returns average execution time of a certain performance */
+  long double get_average_time(std::string perf_name);
+  
+  /** Returns minimum execution time of a certain performance */
+  long double get_min_time(std::string perf_name);
+  
+  /** Returns maximum execution time of a certain performance */
+  long double get_max_time(std::string perf_name);
+  
+  /** Return last measurement of a certain performance */
+  long double get_last_time(std::string perf_name);
+  
+  /** Return the time since the start of the last measurement of a given
+      performance. */
+  long double get_time_so_far(std::string perf_name);
+  
+  /**	Turn off clock, all the Stopwatch::* methods return without doing
+	anything after this method is called. */
+  void turn_off();
+  
+  /** Turn on clock, restore clock operativity after a turn_off(). */
+  void turn_on();
+  
+  /** Take time, depends on mode */
+  long double take_time();
+  
+protected:
+
+  /** Struct to hold the performance data */
+  struct PerformanceData {
+    
+    PerformanceData() :
+      clock_start(0),
+      total_time(0),
+      min_time(0),
+      max_time(0),
+      last_time(0),
+      paused(false),
+      stops(0) {
+    }
+    
+    /** Start time */
+    long double	clock_start;
+    
+    /** Cumulative total time */
+    long double	total_time;
+    
+    /** Minimum time */
+    long double	min_time;
+    
+    /** Maximum time */
+    long double	max_time;
+    
+    /** Last time */
+    long double last_time;
+    
+    /** Tells if this performance has been paused, only for internal use */
+    bool paused;
+    
+    /** How many cycles have been this stopwatch executed? */
+    int	stops;
+  };
+  
+  /** Flag to hold the clock's status */
+  bool active;
+
+  /** Time taking mode */
+  StopwatchMode mode;
+  
+  /** Pointer to the dynamic structure which holds the collection of performance
+      data */
+  std::map<std::string, PerformanceData >* records_of;
+  
+};
+
+Stopwatch& getProfiler();
+
+#ifndef WIN32
+   #pragma GCC visibility pop
+#endif
+
+#endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1be3e52de65d24a33e92392652412e0fe973a3d2..183f0476b82245784a6a263f498f471dcad8b643 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -5,6 +5,7 @@ include_directories("${INCLUDE_DIR}")
 include_directories("${EIGEN3_INCLUDE_DIR}")
 include_directories("${CDD_INCLUDE_DIR}")
 include_directories("${CLP_INCLUDE_DIR}")
+include_directories("${qpOASES_INCLUDE_DIR}")
 
 SET(LIBRARY_NAME ${PROJECT_NAME})
 
@@ -20,6 +21,7 @@ SET(${LIBRARY_NAME}_SOURCES
     solver_LP_clp.cpp
     util.cpp
     logger.cpp
+    stop-watch.cpp
   )
 
 INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src)
@@ -30,6 +32,7 @@ if ( MSVC )
 endif ( MSVC )
 
 TARGET_LINK_LIBRARIES(robust-equilibrium-lib ${CDD_LIBRARY}
+                                             ${qpOASES_LIBRARY}
                                              ${CLP_LIBRARY}
                                               /usr/lib/libCoinUtils.so)
 
diff --git a/src/solver_LP_abstract.cpp b/src/solver_LP_abstract.cpp
index bad6cbac17e8288907aee7b2636c3a92aa405f44..8ea2808f3e8ce83daef328c095df757ea68a65f9 100644
--- a/src/solver_LP_abstract.cpp
+++ b/src/solver_LP_abstract.cpp
@@ -5,6 +5,7 @@
 
 #include <robust-equilibrium-lib/solver_LP_abstract.hh>
 #include <robust-equilibrium-lib/solver_LP_clp.hh>
+#include <robust-equilibrium-lib/solver_LP_qpoases.hh>
 #include <robust-equilibrium-lib/logger.hh>
 #include <iostream>
 
@@ -17,6 +18,8 @@ Solver_LP_abstract* Solver_LP_abstract::getNewSolver(SolverLP solverType)
 {
   if(solverType==SOLVER_LP_CLP)
     return new Solver_LP_clp();
+  if(solverType==SOLVER_LP_QPOASES)
+    return new Solver_LP_qpoases();
 
   SEND_ERROR_MSG("Specified solver type not recognized: "+toString(solverType));
   return NULL;
diff --git a/src/solver_LP_clp.cpp b/src/solver_LP_clp.cpp
index cb3a0b8e76f47b8920fd8efa4c2ee6a3b82761a0..24aa67d84f8c2ddbd1078f990435cf59ce8e4249 100644
--- a/src/solver_LP_clp.cpp
+++ b/src/solver_LP_clp.cpp
@@ -77,6 +77,20 @@ double Solver_LP_clp::getObjectiveValue()
   return m_model.objectiveValue();
 }
 
+void Solver_LP_clp::getDualSolution(Ref_vectorX res)
+{
+  const double *tmp = m_model.dualRowSolution();
+  for(int i=0; i<res.size(); i++)
+    res(i) = tmp[i];
+}
+
+//void Solver_LP_clp::getDualColumnSolution(Ref_vectorX res)
+//{
+//  const double *tmp = m_model.dualColumnSolution();
+//  for(int i=0; i<res.size(); i++)
+//    res(i) = tmp[i];
+//}
+
 unsigned int Solver_LP_clp::getMaximumIterations()
 {
   int integerValue;
diff --git a/src/solver_LP_qpoases.cpp b/src/solver_LP_qpoases.cpp
index ed3b1456d385423d3b32b4006b41de87c0547acb..aef5c2e2c9302ccf1695cb15a7cb6444893b9af3 100644
--- a/src/solver_LP_qpoases.cpp
+++ b/src/solver_LP_qpoases.cpp
@@ -2,3 +2,122 @@
  * Copyright 2015, LAAS-CNRS
  * Author: Andrea Del Prete
  */
+
+#include <robust-equilibrium-lib/solver_LP_qpoases.hh>
+#include <robust-equilibrium-lib/logger.hh>
+
+USING_NAMESPACE_QPOASES
+
+namespace robust_equilibrium
+{
+
+  Solver_LP_qpoases::Solver_LP_qpoases(): Solver_LP_abstract()
+  {
+//    m_options.initialStatusBounds = ST_INACTIVE;
+//    m_options.setToReliable();
+    m_options.setToDefault();
+    m_options.printLevel          = PL_LOW; //PL_NONE
+    m_options.enableRegularisation = BT_TRUE;
+    m_options.enableEqualities = BT_TRUE;
+    m_maxIter = 1000;
+    m_maxTime = 100.0;
+  }
+
+  LP_status Solver_LP_qpoases::solve(Cref_vectorX c, Cref_vectorX lb, Cref_vectorX ub,
+                                     Cref_matrixXX A, Cref_vectorX Alb, Cref_vectorX Aub,
+                                     Ref_vectorX sol)
+  {
+    int n = (int)c.size();  // number of variables
+    int m = (int)A.rows();  // number of constraints
+    assert(lb.size()==n);
+    assert(ub.size()==n);
+    assert(A.cols()==n);
+    assert(Alb.size()==m);
+    assert(Aub.size()==m);
+
+    int iters = m_maxIter;
+    double solutionTime = m_maxTime;
+    if(n!=m_solver.getNV() || m!=m_solver.getNC())
+    {
+      m_solver = SQProblem(n, m, HST_ZERO);
+      m_solver.setOptions(m_options);
+//      m_solver.printOptions();
+      m_init_succeeded = false;
+      m_H = MatrixXX::Zero(n,n);
+    }
+
+//    m_status = m_solver.init(NULL, c.data(), A.data(), lb.data(), ub.data(),
+//                             Alb.data(), Aub.data(), iters, &solutionTime);
+
+    if(!m_init_succeeded)
+    {
+      m_status = m_solver.init(NULL, c.data(), A.data(), lb.data(), ub.data(),
+                               Alb.data(), Aub.data(), iters, &solutionTime);
+      if(m_status==SUCCESSFUL_RETURN)
+        m_init_succeeded = true;
+    }
+    else
+    {
+      // this doesn't work if I pass NULL instead of m_H.data()
+      m_status = m_solver.hotstart(m_H.data(), c.data(), A.data(), lb.data(), ub.data(),
+                                  Alb.data(), Aub.data(), iters, &solutionTime);
+      if(m_status!=SUCCESSFUL_RETURN)
+        m_init_succeeded = false;
+    }
+
+    if(m_status==SUCCESSFUL_RETURN)
+    {
+      m_solver.getPrimalSolution(sol.data());
+    }
+    else
+      SEND_DEBUG_MSG("QPoases solver failed with code "+toString(m_status));
+
+    return getStatus();
+  }
+
+  LP_status Solver_LP_qpoases::getStatus()
+  {
+    int ss = getSimpleStatus(m_status);
+    if(ss==0)
+      return LP_STATUS_OPTIMAL;
+    if(ss==1)
+      return LP_STATUS_MAX_ITER_REACHED;
+    if(ss==-2)
+       return LP_STATUS_INFEASIBLE;
+    if(ss==-3)
+      return LP_STATUS_DUAL_INFEASIBLE;
+    return LP_STATUS_ERROR;
+  }
+
+  double Solver_LP_qpoases::getObjectiveValue()
+  {
+    return m_solver.getObjVal();
+  }
+
+  void Solver_LP_qpoases::getDualSolution(Ref_vectorX res)
+  {
+    m_solver.getDualSolution(res.data());
+  }
+
+  unsigned int Solver_LP_qpoases::getMaximumIterations()
+  {
+    return m_maxIter;
+  }
+
+  bool Solver_LP_qpoases::setMaximumIterations(unsigned int maxIter)
+  {
+    if(maxIter==0)
+      return false;
+    m_maxIter = maxIter;
+    return true;
+  }
+
+  bool Solver_LP_qpoases::setMaximumTime(double seconds)
+  {
+    if(seconds<=0.0)
+      return false;
+    m_maxTime = seconds;
+    return true;
+  }
+
+} // end namespace robust_equilibrium
diff --git a/src/static_equilibrium.cpp b/src/static_equilibrium.cpp
index 3200612c0488c369960ba9255a0c0558b66e72b8..d7697a30dece442e00621fc9d462d04a74361b5a 100644
--- a/src/static_equilibrium.cpp
+++ b/src/static_equilibrium.cpp
@@ -23,6 +23,12 @@ StaticEquilibrium::StaticEquilibrium(double mass, unsigned int generatorsPerCont
     m_is_cdd_initialized = true;
   }
 
+  if(generatorsPerContact!=4)
+  {
+    SEND_WARNING_MSG("Algorithm currently supports only 4 generators per contact!");
+    generatorsPerContact = 4;
+  }
+
   m_solver = Solver_LP_abstract::getNewSolver(solver_type);
 
   m_generatorsPerContact = generatorsPerContact;
@@ -121,53 +127,15 @@ bool StaticEquilibrium::setNewContacts(Cref_matrixX3 contactPoints, Cref_matrixX
   return true;
 }
 
+
 double StaticEquilibrium::computeEquilibriumRobustness(Cref_vector2 com)
 {
-  /*Compute the robustness measure of the equilibrium of a specified CoM position.
-    The operation amounts to solving the following dual LP:
-      find          v
-      minimize      (d+D*com)' v
-      subject to    G' v >= 0
-                    1' G' v = 1
-    where
-      -(d+D c)' v   is the robustness measure
-      c             is the CoM position
-      G             is the matrix whose columns are the gravito-inertial wrench generators
-   */
-  if(m_algorithm!=STATIC_EQUILIBRIUM_ALGORITHM_LP)
-  {
-    SEND_ERROR_MSG("checkRobustEquilibrium is only implemented for the LP algorithm");
-    return false;
-  }
-
-  double robustness_dual, robustness_primal;
-  LP_status lpStatus_primal, lpStatus_dual;
-  long m = m_G_centr.cols(); // number of gravito-inertial wrench generators
-  Vector6 v;
-  VectorX b_b0(m+1);
+  const long m = m_G_centr.cols(); // number of gravito-inertial wrench generators
 
+  if(m_algorithm==STATIC_EQUILIBRIUM_ALGORITHM_LP)
   {
-
-    Vector6 c = m_D*com + m_d;
-    Vector6 lb = Vector6::Ones()*-1e100;
-    Vector6 ub = Vector6::Ones()*1e100;
-    VectorX Alb = VectorX::Zero(m+1);
-    Alb(m) = 1.0;
-    VectorX Aub = VectorX::Ones(m+1)*1e100;
-    Aub(m) = 1.0;
-    MatrixX6 A(m+1,6);
-    A.topRows(m) = m_G_centr.transpose();
-    A.bottomRows<1>() = (m_G_centr*VectorX::Ones(m)).transpose();
-
-    lpStatus_dual = m_solver->solve(c, lb, ub, A, Alb, Aub, v);
-    if(lpStatus_dual==LP_STATUS_OPTIMAL)
-      robustness_dual = m_solver->getObjectiveValue();
-    else
-      SEND_ERROR_MSG("Dual LP problem could not be solved: "+toString(lpStatus_dual));
-  }
-
-  {
-    /* The operation amounts to solving the following LP:
+    /* Compute the robustness measure of the equilibrium of a specified CoM position
+     * by solving the following LP:
           find          b, b0
           minimize      -b0
           subject to    D c + d <= G b    <= D c + d
@@ -178,10 +146,10 @@ double StaticEquilibrium::computeEquilibriumRobustness(Cref_vector2 com)
           c         is the CoM position
           G         is the matrix whose columns are the gravito-inertial wrench generators
     */
-    long m = m_G_centr.cols(); // number of gravito-inertial wrench generators
+    VectorX b_b0(m+1);
     VectorX c = VectorX::Zero(m+1);
     c(m) = -1.0;
-    VectorX lb = -VectorX::Ones(m+1)*1e10;
+    VectorX lb = -VectorX::Ones(m+1)*1e5;
     VectorX ub = VectorX::Ones(m+1)*1e10;
     VectorX Alb = VectorX::Zero(6+m);
     VectorX Aub = VectorX::Ones(6+m)*1e100;
@@ -192,21 +160,84 @@ double StaticEquilibrium::computeEquilibriumRobustness(Cref_vector2 com)
     A.bottomLeftCorner(m,m)   = MatrixXX::Identity(m,m);
     A.bottomRightCorner(m,1)  = -VectorX::Ones(m);
 
-    lpStatus_primal = m_solver->solve(c, lb, ub, A, Alb, Aub, b_b0);
+    LP_status lpStatus_primal = m_solver->solve(c, lb, ub, A, Alb, Aub, b_b0);
+    if(lpStatus_primal==LP_STATUS_OPTIMAL)
+      return -1.0*m_solver->getObjectiveValue();
+
+    SEND_ERROR_MSG("Primal LP problem could not be solved: "+toString(lpStatus_primal));
+    return -1.0;
+  }
+
+  if(m_algorithm==STATIC_EQUILIBRIUM_ALGORITHM_LP2)
+  {
+    /* Compute the robustness measure of the equilibrium of a specified CoM position
+     * by solving the following LP:
+            find          b, b0
+            minimize      -b0
+            subject to    D c + d <= G (b + 1*b0) <= D c + d
+                          0       <= b            <= Inf
+          where
+            b         are the (delta) coefficient of the contact force generators (f = G (b+b0))
+            b0        is the robustness measure
+            c         is the CoM position
+            G         is the matrix whose columns are the gravito-inertial wrench generators
+      */
+    VectorX b_b0(m+1);
+    VectorX c = VectorX::Zero(m+1);
+    c(m) = -1.0;
+    VectorX lb = VectorX::Zero(m+1);
+    lb(m) = -1e10;
+    VectorX ub = VectorX::Ones(m+1)*1e10;
+    MatrixXX A = MatrixXX::Zero(6, m+1);
+    Vector6 Alb = m_D * com + m_d;
+    Vector6 Aub = Alb;
+    A.leftCols(m)  = m_G_centr;
+    A.rightCols(1) = m_G_centr * VectorX::Ones(m);
+
+    LP_status lpStatus_primal = m_solver->solve(c, lb, ub, A, Alb, Aub, b_b0);
     if(lpStatus_primal==LP_STATUS_OPTIMAL)
-      robustness_primal = -1.0*m_solver->getObjectiveValue();
-    else
-      SEND_ERROR_MSG("Primal LP problem could not be solved: "+toString(lpStatus_primal));
+    {
+      return -1.0*m_solver->getObjectiveValue();
+    }
+    SEND_ERROR_MSG("Primal LP problem could not be solved: "+toString(lpStatus_primal));
+    return -1.0;
   }
 
-//  if(lpStatus_primal==LP_STATUS_OPTIMAL && lpStatus_dual==LP_STATUS_OPTIMAL)
-//  {
-//    if(fabs(robustness_dual-robustness_primal)>1e-3)
-//      SEND_ERROR_MSG("Primal and dual solutions differ: "+toString(robustness_primal)+" != "+
-//                     toString(robustness_dual)+" b="+toString(b_b0.transpose()));
-//  }
+  if(m_algorithm==STATIC_EQUILIBRIUM_ALGORITHM_DLP)
+  {
+    /*Compute the robustness measure of the equilibrium of a specified CoM position
+      by solving the following dual LP:
+        find          v
+        minimize      (d+D*com)' v
+        subject to    G' v >= 0
+                      1' G' v = 1
+      where
+        -(d+D c)' v   is the robustness measure
+        c             is the CoM position
+        G             is the matrix whose columns are the gravito-inertial wrench generators
+     */
+    Vector6 v;
+    Vector6 c = m_D*com + m_d;
+    Vector6 lb = Vector6::Ones()*-1e100;
+    Vector6 ub = Vector6::Ones()*1e100;
+    VectorX Alb = VectorX::Zero(m+1);
+    Alb(m) = 1.0;
+    VectorX Aub = VectorX::Ones(m+1)*1e100;
+    Aub(m) = 1.0;
+    MatrixX6 A(m+1,6);
+    A.topRows(m) = m_G_centr.transpose();
+    A.bottomRows<1>() = (m_G_centr*VectorX::Ones(m)).transpose();
+
+    LP_status lpStatus_dual = m_solver->solve(c, lb, ub, A, Alb, Aub, v);
+    if(lpStatus_dual==LP_STATUS_OPTIMAL)
+      return m_solver->getObjectiveValue();
+
+    SEND_ERROR_MSG("Dual LP problem could not be solved: "+toString(lpStatus_dual));
+    return -1.0;
+  }
 
-  return robustness_primal;
+  SEND_ERROR_MSG("checkRobustEquilibrium is only implemented for the LP algorithm");
+  return -1.0;
 }
 
 bool StaticEquilibrium::checkRobustEquilibrium(Cref_vector2 com, double e_max)
diff --git a/src/stop-watch.cpp b/src/stop-watch.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e2c8d4598ce26d3c05faa7a9366cf08b3a6e5ea7
--- /dev/null
+++ b/src/stop-watch.cpp
@@ -0,0 +1,341 @@
+/*
+Copyright (c) 2010-2013 Tommaso Urli
+
+Tommaso Urli    tommaso.urli@uniud.it   University of Udine
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include "sot/torque_control/utils/Stdafx.hh"
+
+#ifndef WIN32
+	#include <sys/time.h>
+#else
+	#include <Windows.h>
+	#include <iomanip>
+#endif
+
+#include <iomanip>      // std::setprecision
+#include "sot/torque_control/utils/stop-watch.hh"
+
+using std::map;
+using std::string;
+using std::ostringstream;
+
+Stopwatch& getProfiler()
+{
+  static Stopwatch s(REAL_TIME);   // alternatives are CPU_TIME and REAL_TIME
+  return s;
+}
+
+Stopwatch::Stopwatch(StopwatchMode _mode) 
+  : active(true), mode(_mode)  
+{
+  records_of = new map<string, PerformanceData>();
+}
+
+Stopwatch::~Stopwatch() 
+{
+  delete records_of;
+}
+
+void Stopwatch::set_mode(StopwatchMode new_mode) 
+{
+  mode = new_mode;
+}
+
+bool Stopwatch::performance_exists(string perf_name) 
+{
+  return (records_of->find(perf_name) != records_of->end());
+}
+
+long double Stopwatch::take_time() 
+{
+  if ( mode == CPU_TIME ) {
+    
+    // Use ctime
+    return clock();
+    
+  } else if ( mode == REAL_TIME ) {
+    
+    // Query operating system
+    
+#ifdef WIN32
+    /*	In case of usage under Windows */
+    FILETIME ft;
+    LARGE_INTEGER intervals;
+    
+    // Get the amount of 100 nanoseconds intervals elapsed since January 1, 1601
+    // (UTC)
+    GetSystemTimeAsFileTime(&ft);
+    intervals.LowPart = ft.dwLowDateTime;
+    intervals.HighPart = ft.dwHighDateTime;
+    
+    long double measure = intervals.QuadPart;
+    measure -= 116444736000000000.0;	// Convert to UNIX epoch time
+    measure /= 10000000.0;		// Convert to seconds
+    
+    return measure;
+#else
+    /* Linux, MacOS, ... */
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    
+    long double measure = tv.tv_usec;
+    measure /= 1000000.0;		// Convert to seconds
+    measure += tv.tv_sec;		// Add seconds part
+    
+    return measure;
+#endif
+    
+  } else {
+    // If mode == NONE, clock has not been initialized, then throw exception
+    throw StopwatchException("Clock not initialized to a time taking mode!");
+  }
+}
+
+void Stopwatch::start(string perf_name)  
+{
+  if (!active) return;
+  
+  // Just works if not already present
+  records_of->insert(make_pair(perf_name, PerformanceData()));
+  
+  PerformanceData& perf_info = records_of->find(perf_name)->second;
+  
+  // Take ctime
+  perf_info.clock_start = take_time();
+  
+  // If this is a new start (i.e. not a restart)
+//  if (!perf_info.paused)
+//    perf_info.last_time = 0;
+  
+  perf_info.paused = false;
+}
+
+void Stopwatch::stop(string perf_name) 
+{
+  if (!active) return;
+  
+  long double clock_end = take_time();
+  
+  // Try to recover performance data
+  if ( !performance_exists(perf_name) )
+    throw StopwatchException("Performance not initialized.");
+  
+  PerformanceData& perf_info = records_of->find(perf_name)->second;
+  
+  perf_info.stops++;
+  long double  lapse = clock_end - perf_info.clock_start;
+  
+  if ( mode == CPU_TIME )
+    lapse /= (double) CLOCKS_PER_SEC;
+  
+  // Update last time
+  perf_info.last_time = lapse;
+  
+  // Update min/max time
+  if ( lapse >= perf_info.max_time )	perf_info.max_time = lapse;
+  if ( lapse <= perf_info.min_time || perf_info.min_time == 0 )	
+    perf_info.min_time = lapse;
+  
+  // Update total time
+  perf_info.total_time += lapse;
+}
+
+void Stopwatch::pause(string perf_name) 
+{
+  if (!active) return;
+  
+  long double  clock_end = clock();
+  
+  // Try to recover performance data
+  if ( !performance_exists(perf_name)  )
+    throw StopwatchException("Performance not initialized.");
+  
+  PerformanceData& perf_info = records_of->find(perf_name)->second;
+  
+  long double  lapse = clock_end - perf_info.clock_start;
+  
+  // Update total time
+  perf_info.last_time += lapse;
+  perf_info.total_time += lapse;
+}
+
+void Stopwatch::reset_all() 
+{
+  if (!active) return;
+  
+  map<string, PerformanceData>::iterator it;
+  
+  for (it = records_of->begin(); it != records_of->end(); ++it) {
+    reset(it->first);
+  }
+}
+
+void Stopwatch::report_all(int precision, std::ostream& output) 
+{
+  if (!active) return;
+  
+  output<< "\n*** PROFILING RESULTS [ms] (min - avg - max - lastTime - nSamples) ***\n";
+  map<string, PerformanceData>::iterator it;
+  for (it = records_of->begin(); it != records_of->end(); ++it) {
+    report(it->first, precision, output);
+  }
+}
+
+void Stopwatch::reset(string perf_name) 
+{
+  if (!active) return;
+  
+  // Try to recover performance data
+  if ( !performance_exists(perf_name)  )
+    throw StopwatchException("Performance not initialized.");
+  
+  PerformanceData& perf_info = records_of->find(perf_name)->second;
+  
+  perf_info.clock_start = 0;
+  perf_info.total_time = 0;
+  perf_info.min_time = 0;
+  perf_info.max_time = 0;
+  perf_info.last_time = 0;
+  perf_info.paused = false;
+  perf_info.stops = 0;
+}
+
+void Stopwatch::turn_on() 
+{
+  std::cout << "Stopwatch active." << std::endl;
+  active = true;
+}
+
+void Stopwatch::turn_off() 
+{
+  std::cout << "Stopwatch inactive." << std::endl;
+	active = false;
+}
+
+void Stopwatch::report(string perf_name, int precision, std::ostream& output) 
+{
+  if (!active) return;
+  
+  // Try to recover performance data
+  if ( !performance_exists(perf_name)  )
+    throw StopwatchException("Performance not initialized.");
+  
+  PerformanceData& perf_info = records_of->find(perf_name)->second;
+  
+  const int MAX_NAME_LENGTH = 40;
+  string pad = "";
+  for (int i = perf_name.length(); i<MAX_NAME_LENGTH; i++)
+    pad.append(" ");
+  
+  output << perf_name << pad;
+  output << std::fixed << std::setprecision(precision) 
+         << (perf_info.min_time*1e3) << "\t";
+  output << std::fixed << std::setprecision(precision) 
+         << (perf_info.total_time*1e3 / (long double) perf_info.stops) << "\t";
+  output << std::fixed << std::setprecision(precision) 
+         << (perf_info.max_time*1e3) << "\t";
+  output << std::fixed << std::setprecision(precision)
+         << (perf_info.last_time*1e3) << "\t";
+  output << std::fixed << std::setprecision(precision)
+         << perf_info.stops << std::endl;
+
+  //	ostringstream stops;
+  //	stops << perf_info.stops;
+  //	output << "  *  Stops " << stops.str() << std::endl;
+  //	output << std::endl;
+}
+
+long double Stopwatch::get_time_so_far(string perf_name) 
+{
+  // Try to recover performance data
+  if ( !performance_exists(perf_name)  )
+    throw StopwatchException("Performance not initialized.");
+  
+  long double lapse = 
+    (take_time() - (records_of->find(perf_name)->second).clock_start);
+  
+  if (mode == CPU_TIME)
+    lapse /= (double) CLOCKS_PER_SEC;
+  
+  return lapse;
+}
+
+long double Stopwatch::get_total_time(string perf_name) 
+{
+  // Try to recover performance data
+  if ( !performance_exists(perf_name)  )
+    throw StopwatchException("Performance not initialized.");
+  
+  PerformanceData& perf_info = records_of->find(perf_name)->second;
+  
+  return perf_info.total_time;
+  
+}
+
+long double Stopwatch::get_average_time(string perf_name) 
+{
+  // Try to recover performance data
+  if ( !performance_exists(perf_name)  )
+    throw StopwatchException("Performance not initialized.");
+  
+  PerformanceData& perf_info = records_of->find(perf_name)->second;
+  
+  return (perf_info.total_time / (long double)perf_info.stops);
+  
+}
+
+long double Stopwatch::get_min_time(string perf_name) 
+{
+  // Try to recover performance data
+  if ( !performance_exists(perf_name)  )
+    throw StopwatchException("Performance not initialized.");
+  
+  PerformanceData& perf_info = records_of->find(perf_name)->second;
+  
+  return perf_info.min_time;
+  
+}
+
+long double Stopwatch::get_max_time(string perf_name) 
+{
+  // Try to recover performance data
+  if ( !performance_exists(perf_name)  )
+    throw StopwatchException("Performance not initialized.");
+  
+  PerformanceData& perf_info = records_of->find(perf_name)->second;
+  
+  return perf_info.max_time;
+  
+}
+
+long double Stopwatch::get_last_time(string perf_name) 
+{
+  // Try to recover performance data
+  if ( !performance_exists(perf_name)  )
+    throw StopwatchException("Performance not initialized.");
+  
+  PerformanceData& perf_info = records_of->find(perf_name)->second;
+  
+  return perf_info.last_time;
+}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index c65796713ddf422483f6c153af5e8ffc2cd4baae..d597f0f6ce8a818a5e9ad5ecd5f1813a6b86bbdc 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -5,6 +5,7 @@ include_directories("${INCLUDE_DIR}")
 include_directories("${EIGEN3_INCLUDE_DIR}")
 include_directories("${CDD_INCLUDE_DIR}")
 include_directories("${CLP_INCLUDE_DIR}")
+include_directories("${qpOASES_INCLUDE_DIR}")
 
 PROJECT(robust-equilibrium-lib)
 
diff --git a/test/test_LP_solvers.cpp b/test/test_LP_solvers.cpp
index 567c464b125c374ac5d53c6fe499dbe6d289f022..5f4bd9e2e856345f1e62d4ae2a881d75c378d691 100644
--- a/test/test_LP_solvers.cpp
+++ b/test/test_LP_solvers.cpp
@@ -8,13 +8,17 @@
 #include "CoinBuild.hpp"
 #include "CoinModel.hpp"
 
+#include <qpOASES.hpp>
+
 #include <robust-equilibrium-lib/solver_LP_clp.hh>
+#include <robust-equilibrium-lib/solver_LP_qpoases.hh>
 
 #include <iostream>
 #include <iomanip>
 
 using namespace std;
 using namespace robust_equilibrium;
+USING_NAMESPACE_QPOASES
 
 /** Example addRows.cpp */
 void test_addRows()
@@ -365,6 +369,35 @@ int main()
 {
   cout <<"Test LP Solvers\n";
 
+  {
+    /* Setup data of first LP. */
+    real_t A[1*2] = { 1.0, 1.0 };
+    real_t g[2] = { 1.5, 1.0 };
+    real_t lb[2] = { 0.5, -2.0 };
+    real_t ub[2] = { 5.0, 2.0 };
+    real_t lbA[1] = { -1.0 };
+    real_t ubA[1] = { 2.0 };
+
+    /* Setup data of second LP. */
+    real_t g_new[2] = { 1.0, 1.5 };
+    real_t lb_new[2] = { 0.0, -1.0 };
+    real_t ub_new[2] = { 5.0, -0.5 };
+    real_t lbA_new[1] = { -2.0 };
+    real_t ubA_new[1] = { 1.0 };
+
+
+    /* Setting up QProblem object with zero Hessian matrix. */
+    QProblem example( 2,1,HST_ZERO );
+
+    Options options;
+    //options.setToMPC();
+    example.setOptions( options );
+
+    /* Solve first LP. */
+    int nWSR = 10;
+    example.init( 0,g,A,lb,ub,lbA,ubA, nWSR,0 );
+  }
+
 //  test_addRows();
   test_small_LP();
 
diff --git a/test/test_static_equilibrium.cpp b/test/test_static_equilibrium.cpp
index ee02e8ccf14cea899c84aeac36858f7b0691d6cd..c36cd787f39a2c52f3e9834d7972b84797b6e6f1 100644
--- a/test/test_static_equilibrium.cpp
+++ b/test/test_static_equilibrium.cpp
@@ -7,12 +7,20 @@
 #include <iostream>
 #include <robust-equilibrium-lib/static_equilibrium.hh>
 #include <robust-equilibrium-lib/logger.hh>
+#include <robust-equilibrium-lib/stop-watch.hh>
 
 using namespace robust_equilibrium;
 using namespace Eigen;
 using namespace std;
 
-
+#define PERF_PP "PP"
+#define PERF_LP_PREPARATION "LP preparation"
+#define PERF_LP_COIN "LP coin"
+#define PERF_LP_OASES "LP oases"
+#define PERF_LP2_COIN "LP2 coin"
+#define PERF_LP2_OASES "LP2 oases"
+#define PERF_DLP_COIN "DLP coin"
+#define PERF_DLP_OASES "DLP oases"
 
 int main()
 {
@@ -30,17 +38,22 @@ int main()
   double LY = 0.5*0.138;         // half foot size in y direction
   RVector3 CONTACT_POINT_LOWER_BOUNDS, CONTACT_POINT_UPPER_BOUNDS;
   CONTACT_POINT_LOWER_BOUNDS << 0.0,  0.0,  0.0;
-  CONTACT_POINT_UPPER_BOUNDS << 0.5,  0.5,  0.0;
+  CONTACT_POINT_UPPER_BOUNDS << 0.5,  0.5,  0.5;
   double gamma = atan(mu);   // half friction cone angle
   RVector3 RPY_LOWER_BOUNDS, RPY_UPPER_BOUNDS;
-  RPY_LOWER_BOUNDS << -0.0*gamma, -0.0*gamma, -M_PI;
-  RPY_UPPER_BOUNDS << +0.0*gamma, +0.0*gamma, +M_PI;
+  RPY_LOWER_BOUNDS << -0*gamma, -0*gamma, -M_PI;
+  RPY_UPPER_BOUNDS << +0*gamma, +0*gamma, +M_PI;
   double X_MARG = 0.07;
   double Y_MARG = 0.07;
-  const int GRID_SIZE = 20;
+  const int GRID_SIZE = 15;
 
   StaticEquilibrium solver_PP(mass, generatorsPerContact, SOLVER_LP_CLP);
-  StaticEquilibrium solver_LP(mass, generatorsPerContact, SOLVER_LP_CLP);
+  StaticEquilibrium solver_LP_coin(mass, generatorsPerContact, SOLVER_LP_CLP);
+  StaticEquilibrium solver_LP_oases(mass, generatorsPerContact, SOLVER_LP_QPOASES);
+  StaticEquilibrium solver_LP2_coin(mass, generatorsPerContact, SOLVER_LP_CLP);
+  StaticEquilibrium solver_LP2_oases(mass, generatorsPerContact, SOLVER_LP_QPOASES);
+  StaticEquilibrium solver_DLP_coin(mass, generatorsPerContact, SOLVER_LP_CLP);
+  StaticEquilibrium solver_DLP_oases(mass, generatorsPerContact, SOLVER_LP_QPOASES);
   MatrixXX contact_pos = MatrixXX::Zero(N_CONTACTS, 3);
   MatrixXX contact_rpy = MatrixXX::Zero(N_CONTACTS, 3);
   MatrixXX p = MatrixXX::Zero(4*N_CONTACTS,3); // contact points
@@ -70,7 +83,7 @@ int main()
         break;
     }
 
-    // generate contact orientation
+//     generate contact orientation
     uniform(RPY_LOWER_BOUNDS, RPY_UPPER_BOUNDS, contact_rpy.row(i));
 
     generate_rectangle_contacts(LX, LY, contact_pos.row(i), contact_rpy.row(i),
@@ -86,13 +99,53 @@ int main()
     printf("Normal (%.3f,%.3f,%.3f)\n", N(i,0), N(i,1), N(i,2));
   }
 
-  if(!solver_LP.setNewContacts(p, N, frictionCoefficients, STATIC_EQUILIBRIUM_ALGORITHM_LP))
+  getProfiler().start(PERF_LP_PREPARATION);
+  if(!solver_LP_coin.setNewContacts(p, N, frictionCoefficients, STATIC_EQUILIBRIUM_ALGORITHM_LP))
+  {
+    printf("Error while setting new contacts");
+    return -1;
+  }
+  getProfiler().stop(PERF_LP_PREPARATION);
+  getProfiler().start(PERF_LP_PREPARATION);
+  if(!solver_LP_oases.setNewContacts(p, N, frictionCoefficients, STATIC_EQUILIBRIUM_ALGORITHM_LP))
+  {
+    printf("Error while setting new contacts");
+    return -1;
+  }
+  getProfiler().stop(PERF_LP_PREPARATION);
+  getProfiler().start(PERF_LP_PREPARATION);
+  if(!solver_LP2_coin.setNewContacts(p, N, frictionCoefficients, STATIC_EQUILIBRIUM_ALGORITHM_LP2))
   {
     printf("Error while setting new contacts");
     return -1;
   }
+  getProfiler().stop(PERF_LP_PREPARATION);
+  getProfiler().start(PERF_LP_PREPARATION);
+  if(!solver_LP2_oases.setNewContacts(p, N, frictionCoefficients, STATIC_EQUILIBRIUM_ALGORITHM_LP2))
+  {
+    printf("Error while setting new contacts");
+    return -1;
+  }
+  getProfiler().stop(PERF_LP_PREPARATION);
+  getProfiler().start(PERF_LP_PREPARATION);
+  if(!solver_DLP_coin.setNewContacts(p, N, frictionCoefficients, STATIC_EQUILIBRIUM_ALGORITHM_DLP))
+  {
+    printf("Error while setting new contacts");
+    return -1;
+  }
+  getProfiler().stop(PERF_LP_PREPARATION);
+  getProfiler().start(PERF_LP_PREPARATION);
+  if(!solver_DLP_oases.setNewContacts(p, N, frictionCoefficients, STATIC_EQUILIBRIUM_ALGORITHM_DLP))
+  {
+    printf("Error while setting new contacts");
+    return -1;
+  }
+  getProfiler().stop(PERF_LP_PREPARATION);
 
-  if(!solver_PP.setNewContacts(p, N, frictionCoefficients, STATIC_EQUILIBRIUM_ALGORITHM_PP))
+  getProfiler().start(PERF_PP);
+  bool res = solver_PP.setNewContacts(p, N, frictionCoefficients, STATIC_EQUILIBRIUM_ALGORITHM_PP);
+  getProfiler().stop(PERF_PP);
+  if(!res)
   {
     printf("Error while setting new contacts");
     return -1;
@@ -121,21 +174,81 @@ int main()
     {
 //      uniform(com_LB, com_UB, com);
       com(0) = x_range(j);
-      double rob = solver_LP.computeEquilibriumRobustness(com);
+
+      getProfiler().start(PERF_LP_COIN);
+      double rob_coin  = solver_LP_coin.computeEquilibriumRobustness(com);
+      getProfiler().stop(PERF_LP_COIN);
+
+      getProfiler().start(PERF_LP_OASES);
+      double rob_oases = solver_LP_oases.computeEquilibriumRobustness(com);
+      getProfiler().stop(PERF_LP_OASES);
+
+      getProfiler().start(PERF_LP2_COIN);
+      double rob_coin2  = solver_LP2_coin.computeEquilibriumRobustness(com);
+      getProfiler().stop(PERF_LP2_COIN);
+
+      getProfiler().start(PERF_LP2_OASES);
+      double rob_oases2 = solver_LP2_oases.computeEquilibriumRobustness(com);
+      getProfiler().stop(PERF_LP2_OASES);
+
+      getProfiler().start(PERF_DLP_COIN);
+      double rob_DLP_coin  = solver_DLP_coin.computeEquilibriumRobustness(com);
+      getProfiler().stop(PERF_DLP_COIN);
+
+      getProfiler().start(PERF_DLP_OASES);
+      double rob_DLP_oases = solver_DLP_oases.computeEquilibriumRobustness(com);
+      getProfiler().stop(PERF_DLP_OASES);
+
+      if(fabs(rob_coin-rob_oases)>1e-5)
+        SEND_ERROR_MSG("LP_coin and LP_oases returned different results: "+toString(rob_coin)+" VS "+toString(rob_oases));
+
+      if(fabs(rob_coin-rob_oases2)>1e-5)
+        SEND_ERROR_MSG("LP_coin and LP2_oases returned different results: "+toString(rob_coin)+" VS "+toString(rob_oases2));
+
+//      if(fabs(rob_coin-rob_coin2)>1e-5)
+//        SEND_ERROR_MSG("LP_coin and LP2_coin returned different results: "+toString(rob_coin)+" VS "+toString(rob_coin2));
+
+      if(fabs(rob_coin-rob_DLP_oases)>1e-5)
+        SEND_ERROR_MSG("LP_coin and DLP_oases returned different results: "+toString(rob_coin)+" VS "+toString(rob_DLP_oases));
+
+      if(fabs(rob_coin-rob_DLP_coin)>1e-5)
+        SEND_ERROR_MSG("LP_coin and DLP_coin returned different results: "+toString(rob_coin)+" VS "+toString(rob_DLP_coin));
+
       if(solver_PP.checkRobustEquilibrium(com, 0.0))
       {
         equilibrium(i,j) = 1.0;
-        if(rob<=0)
-          SEND_ERROR_MSG("PP says com is in equilibrium but LP find negative robustness "+toString(rob));
-        if(rob>9.0)
-          rob = 9.0;
-        printf("%d ", (int)rob);
+        if(rob_coin<=0)
+          SEND_ERROR_MSG("PP says com is in equilibrium but LP_coin find negative robustness "+toString(rob_coin));
+        if(rob_oases<=0)
+          SEND_ERROR_MSG("PP says com is in equilibrium but LP_oases find negative robustness "+toString(rob_oases));
+        if(rob_coin2<=0)
+          SEND_ERROR_MSG("PP says com is in equilibrium but LP_coin2 find negative robustness "+toString(rob_coin2));
+        if(rob_oases2<=0)
+          SEND_ERROR_MSG("PP says com is in equilibrium but LP_oases2 find negative robustness "+toString(rob_oases2));
+        if(rob_DLP_oases<=0)
+          SEND_ERROR_MSG("PP says com is in equilibrium but DLP_oases find negative robustness "+toString(rob_DLP_oases));
+        if(rob_DLP_coin<=0)
+          SEND_ERROR_MSG("PP says com is in equilibrium but DLP_coin negative robustness "+toString(rob_DLP_coin));
+
+        if(rob_coin>9.0)
+          rob_coin = 9.0;
+        printf("%d ", (int)rob_coin);
       }
       else
       {
         equilibrium(i,j) = 0.0;
-        if(rob>0)
-          SEND_ERROR_MSG("PP says com is NOT in equilibrium but LP find positive robustness "+toString(rob));
+        if(rob_coin>0)
+          SEND_ERROR_MSG("PP says com is NOT in equilibrium but LP_coin find positive robustness "+toString(rob_coin));
+        if(rob_oases>0)
+          SEND_ERROR_MSG("PP says com is NOT in equilibrium but LP_oases find positive robustness "+toString(rob_oases));
+        if(rob_coin2>0)
+          SEND_ERROR_MSG("PP says com is NOT in equilibrium but LP_coin2 find positive robustness "+toString(rob_coin2));
+        if(rob_oases2>0)
+          SEND_ERROR_MSG("PP says com is NOT in equilibrium but LP_oases2 find positive robustness "+toString(rob_oases2));
+        if(rob_DLP_coin>0)
+          SEND_ERROR_MSG("PP says com is NOT in equilibrium but DLP_coin find positive robustness "+toString(rob_DLP_coin));
+        if(rob_DLP_oases>0)
+          SEND_ERROR_MSG("PP says com is NOT in equilibrium but DLP_oases find positive robustness "+toString(rob_DLP_oases));
         printf("- ");
       }
 
@@ -154,7 +267,7 @@ int main()
     printf("\n");
   }
 
-  cout<<"Max dist between contact points and grid points "<<minDistContactPoint.maxCoeff()<<"\n";
+//  cout<<"Max dist between contact points and grid points "<<minDistContactPoint.maxCoeff()<<"\n";
 
   cout<<"\nContact point position on the same grid\n";
   bool contactPointDrawn;
@@ -178,5 +291,7 @@ int main()
     printf("\n");
   }
 
+  getProfiler().report_all();
+
   return ret;
 }