//=========================================================================== /*! * * * \author Oswin Krause * \date 2016 * * * \par Copyright 1995-2017 Shark Development Team * *

* This file is part of Shark. * * * Shark 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. * * Shark 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 Shark. If not, see . * */ //=========================================================================== #ifndef SHARK_OBJECTIVEFUNCTIONS_BENCHMARK_MULTIOBJECTIVEBENCHMARK_H #define SHARK_OBJECTIVEFUNCTIONS_BENCHMARK_MULTIOBJECTIVEBENCHMARK_H #include #include #include #include #include #include namespace shark { namespace detail{ //taken from the web. implements an std::integer_sequence type representing a sequence 0,...,N-1, std::integer_sequence is not here until C++14 template struct integer_sequence { using type = integer_sequence; }; template struct integer_sequence_concat; template struct integer_sequence_concat, integer_sequence>: integer_sequence {}; //generate_integer_sequence generates an integer sequence of integers 0....N. requires log(N) template instantiations template struct generate_integer_sequence; template struct generate_integer_sequence: integer_sequence_concat::type, typename generate_integer_sequence::type>::type {}; template <> struct generate_integer_sequence<0>: integer_sequence<>{}; template <> struct generate_integer_sequence<1>: integer_sequence<0>{}; }; /// \brief Creates a multi-objective Benchmark from a set of given single objective functions /// /// A variadic template is used to generate a set of benchmarks. /// eg MultiObjectiveBenchmark sets up a three-objective Benchmark. /// /// A random rotation and translation is applied to each benchmark function, thus /// MultiObjectiveBenchmark forms a non-degenerate front. /// the ith objective can be queried via the get member function. /// /// The generated translations are approximately sampled from the unit ball and starting points are also drawn /// by the same distribution around a random optimum (assuming the optimum is at (0,0) of the untranslated function /// /// Note that all objectives must have scalable dimensionality template class MultiObjectiveBenchmark: public MultiObjectiveFunction{ public: MultiObjectiveBenchmark(std::size_t numVariables = 5){ m_features |= CAN_PROPOSE_STARTING_POINT; m_features |= HAS_FIRST_DERIVATIVE; setupRotations(typename detail::generate_integer_sequence::type()); setNumberOfVariables(numVariables);//prevent that different objectives have different default number of variables. for(auto& f: m_rotations){ //if one function does not have a first derivative, no function has if(!f.hasFirstDerivative()) m_features.reset(HAS_FIRST_DERIVATIVE); } }; ///\brief Name of the Benchmark /// /// The name has the form Objective1/Objective2/Objective3/.../ObjectiveN /// where ObjectiveK is the name of the k-th objective. std::string name()const{ return generateName(typename detail::generate_integer_sequence::type()); } bool hasScalableDimensionality()const{ return true; } void setNumberOfVariables( std::size_t numberOfVariables ){ for(auto& f: m_rotations){ SHARK_RUNTIME_CHECK(f.hasScalableDimensionality(),"Function is not scalable"); f.setNumberOfVariables(numberOfVariables); } } std::size_t numberOfObjectives()const{ return sizeof...(Objectives); } std::size_t numberOfVariables()const{ return get<0>().numberOfVariables(); } template typename std::tuple_element >::type& get(){ return std::get(m_objectives); } template typename std::tuple_element >::type const& get()const{ return std::get(m_objectives); } ///\ Initializes the functions as well as picks random rotations and translations void init() { m_translations.clear(); for(auto& f: m_rotations) { RealVector translation(numberOfVariables()); for(double& v: translation){ v=random::gauss(*mep_rng, 0,1)/std::sqrt(double(numberOfVariables())); } m_translations.push_back(translation); f.setRng(mep_rng); f.init(); } } SearchPointType proposeStartingPoint() const { RealVector x(numberOfVariables()); std::size_t index = random::discrete(0,m_rotations.size()-1); for (std::size_t i = 0; i < x.size(); i++) { x(i) = m_translations[index](i)+random::gauss(*mep_rng, 0,1)/std::sqrt(double(numberOfVariables())); } return x; } /// Returns the vector (f_1(x),...,f_N(x)) of the N objectives in the benchmark for the current point. ResultType eval( SearchPointType const& x ) const { m_evaluationCounter++; ResultType value( numberOfObjectives() ); for(std::size_t i = 0; i != value.size(); ++i){ value(i) = m_rotations[i].eval( x - m_translations[i]); } return value; } /// Calculates function value as well as the the Jacobian( d/dxf_1(x),...,d/dx f_N(x)) of the N objectives in the benchmark for the current point. ResultType evalDerivative( SearchPointType const& x, FirstOrderDerivative& derivative )const { derivative.resize(numberOfObjectives(), numberOfVariables()); RealVector singleDerivative; RealVector value(numberOfObjectives()); for(std::size_t i = 0; i != value.size(); ++i){ value(i) = m_rotations[i].evalDerivative( x - m_translations[i],singleDerivative); noalias(row(derivative,i)) = singleDerivative; } return value; } private: //generate a rotated objective function for each function in the m_objectives tuple template void setupRotations(detail::integer_sequence){ m_rotations.insert(m_rotations.begin(), {RotatedObjectiveFunction(&std::get(m_objectives))... }); } template std::string generateName(detail::integer_sequence)const{ std::string name; for(auto const& fname:{std::get(m_objectives).name()... }){ name+=fname+'/'; } name.pop_back(); return name; } std::tuple m_objectives; std::vector m_rotations; std::vector m_translations; }; } #endif