Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
issue #1865: hpmpc interface
  • Loading branch information
jgillis committed Oct 26, 2016
1 parent 6294146 commit 60608b4
Show file tree
Hide file tree
Showing 33 changed files with 2,134 additions and 88 deletions.
6 changes: 6 additions & 0 deletions .gitmodules
@@ -0,0 +1,6 @@
[submodule "external_packages/hpmpc/src"]
path = external_packages/hpmpc/src
url = https://github.com/jgillis/hpmpc.git
[submodule "external_packages/blasfeo/src"]
path = external_packages/blasfeo/src
url = https://github.com/giaf/blasfeo.git
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -240,7 +240,7 @@ matrix:
- mkdir build
- pushd build
- cmake -DOLD_LLVM=ON -DWITH_ECOS=ON -DWITH_MOSEK=ON -DWITH_WORHP=ON -DWITH_SLICOT=OFF -DWITH_PYTHON=ON -DWITH_JSON=ON ..
- make
- make VERBOSE=1
- sudo make install
- popd
- python -c "from casadi.tools import *;loadAllCompiledPlugins()"
Expand Down
34 changes: 34 additions & 0 deletions CMakeLists.txt
Expand Up @@ -67,6 +67,10 @@ option(WITH_NO_QPOASES_BANNER "Add -D__NO_COPYRIGHT__ to qpOASES definitions" OF
option(WITH_BLOCKSQP "Compile the interface to blockSQP (the source code for blockSQP is included)" ON)
option(WITH_BUILD_DSDP "Compile the the included source code for DSDP" ON)
option(WITH_DSDP "Compile the interface to DSDP" ON)
option(WITH_BUILD_HPMPC "Compile the the included source code for HPMPC" OFF)
option(WITH_HPMPC "Compile the interface to HPMPC" OFF)
option(WITH_BUILD_BLASFEO "Compile the the included source code for BLASFEO" OFF)
option(WITH_BLASFEO "Compile the interface to BLASFEO" OFF)
option(WITH_MOSEK "Compile the interface to MOSEK" OFF)
option(WITH_ECOS "Compile the interface to ECOS" OFF)
option(WITH_BUILD_CSPARSE "Compile the included source code for CSparse" ON)
Expand Down Expand Up @@ -421,6 +425,36 @@ if(WITH_CSPARSE)
endif()
add_feature_info(csparse-interface CSPARSE_FOUND "Interface to the sparse direct linear solver CSparse.")

# BLASFEO
if(WITH_BLASFEO)
if(WITH_BUILD_BLASFEO)
set(BLASFEO_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/external_packages/blasfeo/src/include)
set(BLASFEO_LIBRARIES)
set(BLASFEO_DLOPEN ON)
set(BLASFEO_FOUND ON)
else()
# try to find system blasfeo
find_package(BLASFEO)
set(BLASFEO_DLOPEN OFF)
endif()
endif()
add_feature_info(blasfeo-interface BLASFEO_FOUND "Interface to blasfeo.")

# HPMPC
if(WITH_HPMPC AND BLASFEO_FOUND)
if(WITH_BUILD_HPMPC)
set(HPMPC_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/external_packages/hpmpc/src/include)
set(HPMPC_LIBRARIES)
set(HPMPC_DLOPEN ON)
set(HPMPC_FOUND ON)
else()
# try to find system hpmpc
find_package(HPMPC)
set(HPMPC_DLOPEN OFF)
endif()
endif()
add_feature_info(hpmpc-interface HPMPC_FOUND "Interface to hpmpc.")

# TinyXML
if(WITH_TINYXML)
if(WITH_BUILD_TINYXML)
Expand Down
3 changes: 3 additions & 0 deletions casadi/CMakeLists.txt
Expand Up @@ -86,6 +86,9 @@ macro(casadi_library_or_plugin name is_plugin)
set_property(GLOBAL APPEND PROPERTY CASADI_MODULES ${name})
endmacro()

add_definitions(-DSHARED_LIBRARY_PREFIX="\\"${CMAKE_SHARED_LIBRARY_PREFIX}\\"")
add_definitions(-DSHARED_LIBRARY_SUFFIX="\\"${CMAKE_SHARED_LIBRARY_SUFFIX}\\"")

add_subdirectory(core) # needed by all except external_packages
add_subdirectory(interfaces) # needs external_packages
add_subdirectory(solvers) # needs interfaces
Expand Down
2 changes: 0 additions & 2 deletions casadi/core/CMakeLists.txt
@@ -1,8 +1,6 @@
cmake_minimum_required(VERSION 2.8.6)

# Make the shared library prefix and suffix available in C++
add_definitions(-DSHARED_LIBRARY_PREFIX="${CMAKE_SHARED_LIBRARY_PREFIX}")
add_definitions(-DSHARED_LIBRARY_SUFFIX="${CMAKE_SHARED_LIBRARY_SUFFIX}")

add_subdirectory(runtime)

Expand Down
2 changes: 2 additions & 0 deletions casadi/core/casadi_types.hpp
Expand Up @@ -388,6 +388,8 @@ namespace casadi {
CONIC_X0,
/// dense
CONIC_LAM_X0,
/// dense
CONIC_LAM_A0,
CONIC_NUM_IN};

/// Output arguments of an QP Solver
Expand Down
42 changes: 42 additions & 0 deletions casadi/core/function/conic.cpp
Expand Up @@ -86,6 +86,7 @@ namespace casadi {
case CONIC_UBX: return "ubx";
case CONIC_X0: return "x0";
case CONIC_LAM_X0: return "lam_x0";
case CONIC_LAM_A0: return "lam_a0";
case CONIC_NUM_IN: break;
}
return string();
Expand Down Expand Up @@ -183,6 +184,7 @@ namespace casadi {
w[CONIC_UBA] = ret_in[NLPSOL_UBG] - v.at(3);
w[CONIC_X0] = ret_in[NLPSOL_X0];
w[CONIC_LAM_X0] = ret_in[NLPSOL_LAM_X0];
w[CONIC_LAM_A0] = ret_in[NLPSOL_LAM_G0];
w = conic_f(w);

// Get expressions for the solution
Expand Down Expand Up @@ -256,6 +258,7 @@ namespace casadi {
return get_sparsity_out(CONIC_X);
case CONIC_LBA:
case CONIC_UBA:
case CONIC_LAM_A0:
return get_sparsity_out(CONIC_LAM_A);
case CONIC_A:
return A_;
Expand Down Expand Up @@ -352,4 +355,43 @@ namespace casadi {
}
}

void Conic::print_fstats(const ConicMemory* m) const {

size_t maxNameLen=0;

// Retrieve all qp keys
std::vector<std::string> keys;
for (auto &&s : m->fstats) {
maxNameLen = max(s.first.size(), maxNameLen);
keys.push_back(s.first);
}

// Print header
std::stringstream s;
std::string blankName(maxNameLen, ' ');
s
<< blankName
<< " proc wall num mean mean"
<< endl << blankName
<< " time time evals proc time wall time";
userOut() << s.str() << endl;

std::sort(keys.begin(), keys.end());
for (auto k : keys) {
const FStats& fs = m->fstats.at(k);
print_stats_line(maxNameLen, k, fs.n_call, fs.t_proc, fs.t_wall);
}

// Sum the previously printed stats
double t_wall_all_previous = 0;
double t_proc_all_previous = 0;
for (auto k : keys) {
const FStats& fs = m->fstats.at(k);
t_proc_all_previous += fs.t_proc;
t_wall_all_previous += fs.t_wall;
}
print_stats_line(maxNameLen, "all previous", -1, t_proc_all_previous, t_wall_all_previous);

}

} // namespace casadi
10 changes: 10 additions & 0 deletions casadi/core/function/conic_impl.hpp
Expand Up @@ -29,9 +29,16 @@
#include "conic.hpp"
#include "function_internal.hpp"
#include "plugin_interface.hpp"
#include "../timing.hpp"

/// \cond INTERNAL
namespace casadi {

struct CASADI_EXPORT ConicMemory {
// Function specific statistics
std::map<std::string, FStats> fstats;
};

/// Internal class
class CASADI_EXPORT Conic : public FunctionInternal, public PluginInterface<Conic> {
public:
Expand Down Expand Up @@ -98,6 +105,9 @@ namespace casadi {
/// Can discrete variables be treated
virtual bool integer_support() const { return false;}

/// Print statistics
void print_fstats(const ConicMemory* m) const;

protected:
/// Options
std::vector<bool> discrete_;
Expand Down
69 changes: 68 additions & 1 deletion casadi/core/function/function_internal.cpp
Expand Up @@ -35,6 +35,7 @@
#include <cstdlib>
#include <ctime>
#endif // WITH_DL
#include <iomanip>

using namespace std;

Expand Down Expand Up @@ -179,11 +180,16 @@ namespace casadi {
{"max_num_dir",
{OT_INT,
"Specify the maximum number of directions for derivative functions."
" Overrules the builtin optimized_num_dir."}}
" Overrules the builtin optimized_num_dir."}},
{"print_time",
{OT_BOOL,
"print information about execution time"}}
}
};

void FunctionInternal::init(const Dict& opts) {

print_time_ = true;
// Read options
for (auto&& op : opts) {
if (op.first=="verbose") {
Expand Down Expand Up @@ -216,6 +222,8 @@ namespace casadi {
ad_weight_sp_ = op.second;
} else if (op.first=="max_num_dir") {
max_num_dir_ = op.second;
} else if (op.first=="print_time") {
print_time_ = op.second;
}
}

Expand Down Expand Up @@ -3175,4 +3183,63 @@ namespace casadi {
return singleton;
}

// Convert a float to a string of an exact length.
// First it tries fixed precision, then falls back to exponential notation.
//
// todo(jaeandersson,jgillis): needs either review or unit tests
// because it throws exceptions if it fail.
std::string formatFloat(double x, int totalWidth, int maxPrecision, int fallbackPrecision) {
std::ostringstream out0;
out0 << fixed << setw(totalWidth) << setprecision(maxPrecision) << x;
std::string ret0 = out0.str();
if (ret0.length() == totalWidth) {
return ret0;
} else if (ret0.length() > totalWidth) {
std::ostringstream out1;
out1 << setw(totalWidth) << setprecision(fallbackPrecision) << x;
std::string ret1 = out1.str();
if (ret1.length() != totalWidth)
casadi_error(
"ipopt timing formatting fallback is bugged, sorry about that."
<< "expected " << totalWidth << " digits, but got " << ret1.length()
<< ", string: \"" << ret1 << "\", number: " << x);
return ret1;
} else {
casadi_error("ipopt timing formatting is bugged, sorry about that.");
}
}

void FunctionInternal::print_stats_line(int maxNameLen, std::string label,
double n_call, double t_proc, double t_wall) {
// Skip when not called
if (n_call == 0) return;

std::stringstream s;

s
<< setw(maxNameLen) << label << " "
<< formatFloat(t_proc, 9, 3, 3) << " [s] "
<< formatFloat(t_wall, 9, 3, 3) << " [s]";
if (n_call == -1) {
// things like main loop don't have # evals
s << endl;
} else {
s
<< " "
<< setw(5) << n_call;
if (n_call < 2) {
s << endl;
} else {
// only print averages if there is more than 1 eval
s
<< " "
<< formatFloat(1000.0*t_proc/n_call, 10, 2, 3) << " [ms] "
<< formatFloat(1000.0*t_wall/n_call, 10, 2, 3) << " [ms]"
<< endl;
}
}
userOut() << s.str();
}


} // namespace casadi
6 changes: 6 additions & 0 deletions casadi/core/function/function_internal.hpp
Expand Up @@ -844,6 +844,9 @@ namespace casadi {
/// Errors are thrown if numerical values of inputs look bad
bool inputs_check_;

// Print timing statistics
bool print_time_;

/** \brief Get type name */
virtual std::string type_name() const;

Expand All @@ -862,6 +865,9 @@ namespace casadi {
template<typename MatType>
std::vector<std::vector<MatType> > symbolicAdjSeed(int nadj, const std::vector<MatType>& v);

protected:
static void print_stats_line(int maxNameLen, std::string label, double n_call,
double t_proc, double t_wall);
private:
/// Memory objects
std::vector<void*> mem_;
Expand Down
5 changes: 0 additions & 5 deletions casadi/core/function/nlpsol.cpp
Expand Up @@ -228,9 +228,6 @@ namespace casadi {
{OT_BOOL,
"When errors occur during evaluation of f,g,...,"
"stop the iterations"}},
{"print_time",
{OT_BOOL,
"print information about execution time"}},
{"verbose_init",
{OT_BOOL,
"Print out timing information about "
Expand Down Expand Up @@ -262,8 +259,6 @@ namespace casadi {
warn_initial_bounds_ = op.second;
} else if (op.first=="iteration_callback_ignore_errors") {
iteration_callback_ignore_errors_ = op.second;
} else if (op.first=="print_time") {
print_time_ = op.second;
} else if (op.first=="discrete") {
discrete_ = op.second;
}
Expand Down
3 changes: 0 additions & 3 deletions casadi/core/function/nlpsol_impl.hpp
Expand Up @@ -79,9 +79,6 @@ namespace casadi {
// Ignore errors in the iteration callbacks
bool iteration_callback_ignore_errors_;

// Print timing statistics
bool print_time_;

/// Which variables are discrete?
std::vector<bool> discrete_;

Expand Down
58 changes: 0 additions & 58 deletions casadi/core/function/oracle_function.cpp
Expand Up @@ -262,64 +262,6 @@ namespace casadi {
oracle_ = oracle_.expand();
}

// Convert a float to a string of an exact length.
// First it tries fixed precision, then falls back to exponential notation.
//
// todo(jaeandersson,jgillis): needs either review or unit tests
// because it throws exceptions if it fail.
std::string formatFloat(double x, int totalWidth, int maxPrecision, int fallbackPrecision) {
std::ostringstream out0;
out0 << fixed << setw(totalWidth) << setprecision(maxPrecision) << x;
std::string ret0 = out0.str();
if (ret0.length() == totalWidth) {
return ret0;
} else if (ret0.length() > totalWidth) {
std::ostringstream out1;
out1 << setw(totalWidth) << setprecision(fallbackPrecision) << x;
std::string ret1 = out1.str();
if (ret1.length() != totalWidth)
casadi_error(
"ipopt timing formatting fallback is bugged, sorry about that."
<< "expected " << totalWidth << " digits, but got " << ret1.length()
<< ", string: \"" << ret1 << "\", number: " << x);
return ret1;
} else {
casadi_error("ipopt timing formatting is bugged, sorry about that.");
}
}

void print_stats_line(int maxNameLen, std::string label,
double n_call, double t_proc, double t_wall) {
// Skip when not called
if (n_call == 0) return;

std::stringstream s;

s
<< setw(maxNameLen) << label << " "
<< formatFloat(t_proc, 9, 3, 3) << " [s] "
<< formatFloat(t_wall, 9, 3, 3) << " [s]";
if (n_call == -1) {
// things like main loop don't have # evals
s << endl;
} else {
s
<< " "
<< setw(5) << n_call;
if (n_call < 2) {
s << endl;
} else {
// only print averages if there is more than 1 eval
s
<< " "
<< formatFloat(1000.0*t_proc/n_call, 10, 2, 3) << " [ms] "
<< formatFloat(1000.0*t_wall/n_call, 10, 2, 3) << " [ms]"
<< endl;
}
}
userOut() << s.str();
}

void OracleFunction::print_fstats(const OracleMemory* m) const {

size_t maxNameLen=0;
Expand Down

0 comments on commit 60608b4

Please sign in to comment.