From 13b760c6e7c2e8e9678529f0534a5008e369ec95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Darricau?= Date: Wed, 15 Apr 2015 12:00:41 +0900 Subject: [PATCH 1/2] Wrapping to Eigen::internal::set_is_malloc_allowed done --- CMakeLists.txt | 1 + include/roboptim/core/alloc.hh | 35 ++++++++++++++++++ .../decorator/finite-difference-gradient.hxx | 8 +++- .../roboptim/core/differentiable-function.hh | 8 ++-- .../roboptim/core/differentiable-function.hxx | 5 +-- include/roboptim/core/function.hh | 7 ++-- .../core/n-times-derivable-function.hh | 14 ++++++- .../core/numeric-quadratic-function.hxx | 7 +++- include/roboptim/core/sum-of-c1-squares.hxx | 10 +---- .../core/twice-differentiable-function.hh | 4 +- src/CMakeLists.txt | 1 + src/alloc.cc | 37 +++++++++++++++++++ tests/detail-utility.cc | 4 +- tests/function-pool.cc | 4 +- tests/ref.cc | 4 +- 15 files changed, 116 insertions(+), 33 deletions(-) create mode 100644 include/roboptim/core/alloc.hh create mode 100644 src/alloc.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index a1b65f722..bafaab2ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ SET(PROJECT_URL "http://github.com/roboptim/roboptim-core") SET(HEADERS ${CMAKE_SOURCE_DIR}/include/roboptim/core.hh + ${CMAKE_SOURCE_DIR}/include/roboptim/core/alloc.hh ${CMAKE_SOURCE_DIR}/include/roboptim/core/cache.hh ${CMAKE_SOURCE_DIR}/include/roboptim/core/cache.hxx ${CMAKE_SOURCE_DIR}/include/roboptim/core/callback/multiplexer.hh diff --git a/include/roboptim/core/alloc.hh b/include/roboptim/core/alloc.hh new file mode 100644 index 000000000..d12a024b3 --- /dev/null +++ b/include/roboptim/core/alloc.hh @@ -0,0 +1,35 @@ +// Copyright (C) 2015 by Félix Darricau, AIST, CNRS, EPITA +// +// This file is part of the roboptim. +// +// roboptim is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// roboptim is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with roboptim. If not, see . + +#ifndef ROBOPTIM_CORE_ALLOC_HH +# define ROBOPTIM_CORE_ALLOC_HH + +# include + +# define EIGEN_RUNTIME_NO_MALLOC +# include + +namespace roboptim +{ + ROBOPTIM_LOCAL + bool is_malloc_allowed_update(bool update, bool new_value); + + ROBOPTIM_DLLAPI + bool set_is_malloc_allowed (bool allow); +} + +#endif //! ROBOPTIM_CORE_ALLOC_HH diff --git a/include/roboptim/core/decorator/finite-difference-gradient.hxx b/include/roboptim/core/decorator/finite-difference-gradient.hxx index 2135ec4d5..efc4d34f7 100644 --- a/include/roboptim/core/decorator/finite-difference-gradient.hxx +++ b/include/roboptim/core/decorator/finite-difference-gradient.hxx @@ -403,7 +403,7 @@ namespace roboptim argument_ref xEps) const { #ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (true); + set_is_malloc_allowed (true); #endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION typedef Eigen::Triplet triplet_t; @@ -431,6 +431,10 @@ namespace roboptim } } jacobian.setFromTriplets (coefficients.begin (), coefficients.end ()); + +#ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION + set_is_malloc_allowed (false); +#endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION } template @@ -668,7 +672,7 @@ namespace roboptim argument_ref xEps) const { #ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (true); + set_is_malloc_allowed (true); #endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION typedef Eigen::Triplet triplet_t; diff --git a/include/roboptim/core/differentiable-function.hh b/include/roboptim/core/differentiable-function.hh index a7f99e28d..e7eac7dfd 100644 --- a/include/roboptim/core/differentiable-function.hh +++ b/include/roboptim/core/differentiable-function.hh @@ -150,11 +150,11 @@ namespace roboptim assert (argument.size () == this->inputSize ()); assert (isValidJacobian (jacobian)); #ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (false); + set_is_malloc_allowed (false); #endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION this->impl_jacobian (jacobian, argument); #ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (true); + set_is_malloc_allowed (true); #endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION assert (isValidJacobian (jacobian)); } @@ -194,11 +194,11 @@ namespace roboptim assert (argument.size () == this->inputSize ()); assert (isValidGradient (gradient)); #ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (false); + set_is_malloc_allowed (false); #endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION this->impl_gradient (gradient, argument, functionId); #ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (true); + set_is_malloc_allowed (true); #endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION assert (isValidGradient (gradient)); } diff --git a/include/roboptim/core/differentiable-function.hxx b/include/roboptim/core/differentiable-function.hxx index 59de80667..133800eac 100644 --- a/include/roboptim/core/differentiable-function.hxx +++ b/include/roboptim/core/differentiable-function.hxx @@ -37,12 +37,9 @@ namespace roboptim (jacobian_ref jacobian, const_argument_ref argument) const { -#ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (true); -#endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION - typedef Eigen::Triplet triplet_t; std::vector coefficients; + for (jacobian_t::Index i = 0; i < this->outputSize (); ++i) { gradient_t grad = gradient (argument, i); diff --git a/include/roboptim/core/function.hh b/include/roboptim/core/function.hh index ab3929d12..7e2995f8b 100644 --- a/include/roboptim/core/function.hh +++ b/include/roboptim/core/function.hh @@ -33,7 +33,8 @@ # include # define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET -# define EIGEN_RUNTIME_NO_MALLOC + +# include # include # include # include @@ -476,11 +477,11 @@ namespace roboptim assert (argument.size () == inputSize ()); assert (isValidResult (result)); #ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (false); + set_is_malloc_allowed (false); #endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION this->impl_compute (result, argument); #ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (true); + set_is_malloc_allowed (true); #endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION assert (isValidResult (result)); } diff --git a/include/roboptim/core/n-times-derivable-function.hh b/include/roboptim/core/n-times-derivable-function.hh index 384cf1e41..ae495d84c 100644 --- a/include/roboptim/core/n-times-derivable-function.hh +++ b/include/roboptim/core/n-times-derivable-function.hh @@ -213,10 +213,15 @@ namespace roboptim size_type functionId = 0) const { #ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (true); + set_is_malloc_allowed (true); #endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION derivative_t derivative (derivativeSize ()); + +#ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION + set_is_malloc_allowed (false); +#endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION + derivative.setZero (); this->derivative (derivative, argument[0], 1); @@ -250,12 +255,17 @@ namespace roboptim size_type functionId = 0) const { # ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (true); + set_is_malloc_allowed (true); # endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION assert (functionId == 0); derivative_t derivative (derivativeSize ()); + +#ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION + set_is_malloc_allowed (false); +#endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION + derivative.setZero (); this->derivative (derivative, argument[0], 2); diff --git a/include/roboptim/core/numeric-quadratic-function.hxx b/include/roboptim/core/numeric-quadratic-function.hxx index 49d2e607e..7ad8d2e21 100644 --- a/include/roboptim/core/numeric-quadratic-function.hxx +++ b/include/roboptim/core/numeric-quadratic-function.hxx @@ -77,10 +77,15 @@ namespace roboptim (jacobian_ref jacobian, const_argument_ref x) const { #ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (true); + set_is_malloc_allowed (true); #endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION Eigen::MatrixXd j = 2 * x.transpose () * a_; + +#ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION + set_is_malloc_allowed (false); +#endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION + for (size_type i = 0; i < this->inputSize (); ++i) j.coeffRef (0, i) += b_[i]; diff --git a/include/roboptim/core/sum-of-c1-squares.hxx b/include/roboptim/core/sum-of-c1-squares.hxx index 882aafe31..fe35c934e 100644 --- a/include/roboptim/core/sum-of-c1-squares.hxx +++ b/include/roboptim/core/sum-of-c1-squares.hxx @@ -62,13 +62,9 @@ namespace roboptim { void GenericSumOfC1Squares:: impl_compute(result_ref result, const_argument_ref x) const { -#ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (true); -#endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION - computeFunction (x); value_type sumSquares = 0; - for (size_t i = 0; i < value_.size(); i++) { + for (typename result_t::Index i = 0; i < value_.size(); i++) { value_type y = value_[i]; sumSquares += y*y; } @@ -80,10 +76,6 @@ namespace roboptim { impl_gradient(gradient_ref gradient, const_argument_ref x, size_type ROBOPTIM_DEBUG_ONLY (row)) const { -#ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (true); -#endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION - assert (row == 0); computeFunction (x); gradient.setZero (); diff --git a/include/roboptim/core/twice-differentiable-function.hh b/include/roboptim/core/twice-differentiable-function.hh index 73df35ccf..d0cdfa0ee 100644 --- a/include/roboptim/core/twice-differentiable-function.hh +++ b/include/roboptim/core/twice-differentiable-function.hh @@ -126,11 +126,11 @@ namespace roboptim "Evaluating hessian at point: " << argument); assert (isValidHessian (hessian)); #ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (false); + set_is_malloc_allowed (false); #endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION this->impl_hessian (hessian, argument, functionId); #ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (true); + set_is_malloc_allowed (true); #endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION assert (isValidHessian (hessian)); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4f0fb575d..508f1d043 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,6 +24,7 @@ ADD_LIBRARY(roboptim-core SHARED ${HEADERS} debug.hh doc.hh + alloc.cc finite-difference-gradient.cc generic-solver.cc indent.cc diff --git a/src/alloc.cc b/src/alloc.cc new file mode 100644 index 000000000..ccaa23eed --- /dev/null +++ b/src/alloc.cc @@ -0,0 +1,37 @@ +// Copyright (C) 2015 by Félix Darricau, AIST, CNRS, EPITA +// +// This file is part of the roboptim. +// +// roboptim is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// roboptim is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with roboptim. If not, see . + +#include "roboptim/core/alloc.hh" + +namespace roboptim +{ + bool is_malloc_allowed_update(bool update = false, bool new_value = false) + { + static bool value = true; + if (update) + value = new_value; + return value; + } + + /// \brief Manage the calls to Eigen::set_is_malloc_allowed. + bool set_is_malloc_allowed (bool allow) + { + is_malloc_allowed_update(true, allow); + + return Eigen::internal::set_is_malloc_allowed(allow); + } +} // end of namespace roboptim. diff --git a/tests/detail-utility.cc b/tests/detail-utility.cc index bada6758d..fdc26b326 100644 --- a/tests/detail-utility.cc +++ b/tests/detail-utility.cc @@ -58,9 +58,9 @@ namespace detail matrix_t m (2, 2); m << 1., 2., 3., 4.; - internal::set_is_malloc_allowed (false); + set_is_malloc_allowed (false); foo (m.row (1)); - internal::set_is_malloc_allowed (true); + set_is_malloc_allowed (true); BOOST_CHECK (!m.row (0).isZero ()); BOOST_CHECK (m.row (1).isZero ()); diff --git a/tests/function-pool.cc b/tests/function-pool.cc index 72b456479..17f50d8c6 100644 --- a/tests/function-pool.cc +++ b/tests/function-pool.cc @@ -306,7 +306,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE (function_pool, T, functionTypes_t) "Joint position pool"); #ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (true); + set_is_malloc_allowed (true); #endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION // Pre-allocate memory @@ -325,7 +325,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE (function_pool, T, functionTypes_t) fd_denseJac (pool->outputSize (), pool->inputSize ()); #ifndef ROBOPTIM_DO_NOT_CHECK_ALLOCATION - Eigen::internal::set_is_malloc_allowed (false); + set_is_malloc_allowed (false); #endif //! ROBOPTIM_DO_NOT_CHECK_ALLOCATION // Call the pool diff --git a/tests/ref.cc b/tests/ref.cc index 90f631dd4..f02003ffa 100644 --- a/tests/ref.cc +++ b/tests/ref.cc @@ -88,9 +88,9 @@ BOOST_AUTO_TEST_CASE (ref) F::jacobian_ref jac_ref (jac); F::const_argument_ref x_ref (map_x); - Eigen::internal::set_is_malloc_allowed (false); + set_is_malloc_allowed (false); f.jacobian (jac_ref, x_ref); - Eigen::internal::set_is_malloc_allowed (true); + set_is_malloc_allowed (true); (*output) << map_x << std::endl; (*output) << f << std::endl; From 8240ecbbe006335d5778ca4a013e505c04004d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Darricau?= Date: Wed, 15 Apr 2015 12:01:43 +0900 Subject: [PATCH 2/2] Test for sum-of-c1-squares written --- tests/CMakeLists.txt | 3 + tests/sum-of-c1-squares.cc | 111 +++++++++++++++++++++++++++++++++ tests/sum-of-c1-squares.stdout | 5 ++ 3 files changed, 119 insertions(+) create mode 100644 tests/sum-of-c1-squares.cc create mode 100644 tests/sum-of-c1-squares.stdout diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 53e6cabf0..bf89ce24c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -122,6 +122,9 @@ ROBOPTIM_CORE_TEST(function-identity) ROBOPTIM_CORE_TEST(function-sin) ROBOPTIM_CORE_TEST(function-polynomial) +# Sum Of C1 Squares. +ROBOPTIM_CORE_TEST(sum-of-c1-squares) + # Decorators. ROBOPTIM_CORE_TEST(decorator-cached-function) ROBOPTIM_CORE_TEST(decorator-finite-difference-gradient) diff --git a/tests/sum-of-c1-squares.cc b/tests/sum-of-c1-squares.cc new file mode 100644 index 000000000..65f24061a --- /dev/null +++ b/tests/sum-of-c1-squares.cc @@ -0,0 +1,111 @@ +// Copyright (C) 2015 by Félix Darricau, AIST, CNRS, EPITA +// +// This file is part of the roboptim. +// +// roboptim is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// roboptim is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with roboptim. If not, see . + +#include "shared-tests/fixture.hh" + +#include + +#include +#include + +using namespace roboptim; + +struct F : public DifferentiableFunction +{ + F () : DifferentiableFunction (4, 2, + "x₀ * x₃ * (x₀ + x₁ + x₂) + x₃, " + "x₀²") + { + } + + void + impl_compute (result_ref result, const_argument_ref x) const + { + result (0) = x[0] * x[3] * (x[0] + x[1] + x[2]) + x[3]; + result (1) = x[0] * x[0]; + } + + void + impl_gradient (gradient_ref grad, const_argument_ref x, + size_type functionId) const + { + switch (functionId) + { + case 0: + { + grad[0] = x[0] * x[3] + x[3] * (x[0] + x[1] + x[2]); + grad[1] = x[0] * x[3]; + grad[2] = x[0] * x[3] + 1; + grad[3] = x[0] * (x[0] + x[1] + x[2]); + } + break; + + case 1: + { + grad[0] = 2. * x[0]; + } + break; + + default: + abort (); + } + } +}; + +BOOST_FIXTURE_TEST_SUITE (core, TestSuiteConfiguration) + +BOOST_AUTO_TEST_CASE (sum_of_c1_squares) +{ + boost::shared_ptr + output = retrievePattern ("sum-of-c1-squares"); + + boost::shared_ptr fptr = + boost::make_shared(); + + SumOfC1Squares fSum(fptr, "null"); + + SumOfC1Squares::vector_t x (4); + x << 1., 2., 1., 2.; + SumOfC1Squares::gradient_t grad (fSum.gradientSize ()); + + (*output) << fSum << std::endl; + + BOOST_CHECK (fSum.inputSize () == 4); + + BOOST_CHECK (fSum.outputSize () == 1); + + BOOST_CHECK (fSum.getName () == "null"); + + BOOST_CHECK (fSum.isValidResult (fSum (x))); + + BOOST_CHECK (fSum(x)[0] == 101); + + (*output) << fSum.gradient (x) << std::endl; + + fSum.gradient (grad, x); + (*output) << grad << std::endl; + + BOOST_CHECK (fSum.gradientSize () == 4); + + BOOST_CHECK (fSum.isValidGradient (fSum.gradient (x))); + + + std::cout << output->str () << std::endl; + BOOST_CHECK (output->match_pattern ()); +} + +BOOST_AUTO_TEST_SUITE_END () diff --git a/tests/sum-of-c1-squares.stdout b/tests/sum-of-c1-squares.stdout new file mode 100644 index 000000000..f9901685d --- /dev/null +++ b/tests/sum-of-c1-squares.stdout @@ -0,0 +1,5 @@ +null (differentiable function) +[4](204,40,60,80) +[4](204,40,60,80) +4 +1