MultiObjectiveBenchmark.h
Go to the documentation of this file.
1//===========================================================================
2/*!
3 *
4 *
5 * \author Oswin Krause
6 * \date 2016
7 *
8 *
9 * \par Copyright 1995-2017 Shark Development Team
10 *
11 * <BR><HR>
12 * This file is part of Shark.
13 * <https://shark-ml.github.io/Shark/>
14 *
15 * Shark is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU Lesser General Public License as published
17 * by the Free Software Foundation, either version 3 of the License, or
18 * (at your option) any later version.
19 *
20 * Shark is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public License
26 * along with Shark. If not, see <http://www.gnu.org/licenses/>.
27 *
28 */
29//===========================================================================
30#ifndef SHARK_OBJECTIVEFUNCTIONS_BENCHMARK_MULTIOBJECTIVEBENCHMARK_H
31#define SHARK_OBJECTIVEFUNCTIONS_BENCHMARK_MULTIOBJECTIVEBENCHMARK_H
32
36#include <shark/Core/Random.h>
37
39#include <tuple>
40
41namespace shark {namespace benchmarks{
42
43namespace detail{
44 //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
45 template<int...> struct integer_sequence { using type = integer_sequence; };
46 template<typename T1, typename T2> struct integer_sequence_concat;
47 template<int... I1, int... I2> struct integer_sequence_concat<integer_sequence<I1...>, integer_sequence<I2...>>: integer_sequence<I1..., (sizeof...(I1) + I2)...> {};
48
49 //generate_integer_sequence generates an integer sequence of integers 0....N. requires log(N) template instantiations
50 template<int N> struct generate_integer_sequence;
51 template<int N> struct generate_integer_sequence: integer_sequence_concat<typename generate_integer_sequence<N/2>::type, typename generate_integer_sequence<N-N/2>::type>::type {};
52 template <> struct generate_integer_sequence<0>: integer_sequence<>{};
53 template <> struct generate_integer_sequence<1>: integer_sequence<0>{};
54};
55
56/// \brief Creates a multi-objective Benchmark from a set of given single objective functions
57///
58/// A variadic template is used to generate a set of benchmarks.
59/// eg MultiObjectiveBenchmark<Sphere,Ellispoid,Rosenbrock> sets up a three-objective Benchmark.
60///
61/// A random rotation and translation is applied to each benchmark function, thus
62/// MultiObjectiveBenchmark<Sphere,Sphere> forms a non-degenerate front.
63/// the k-th objective can be queried via the get<k> member function.
64///
65/// The generated translations are approximately sampled from the unit ball and starting points are also drawn
66/// by the same distribution around a random optimum (assuming the optimum is at (0,0) of the untranslated function
67///
68/// Note that all objectives must have scalable dimensionality
69/// \ingroup benchmarks
70template<class ... Objectives>
72public:
73 MultiObjectiveBenchmark(std::size_t numVariables = 5){
76 setupRotations(typename detail::generate_integer_sequence<sizeof...(Objectives)>::type());
77 setNumberOfVariables(numVariables);//prevent that different objectives have different default number of variables.
78 for(auto& f: m_rotations){
79 //if one function does not have a first derivative, no function has
80 if(!f.hasFirstDerivative())
82 }
83 };
84
85 ///\brief Name of the Benchmark
86 ///
87 /// The name has the form Objective1/Objective2/Objective3/.../ObjectiveN
88 /// where ObjectiveK is the name of the k-th objective.
89 std::string name()const{
90 return generateName(typename detail::generate_integer_sequence<sizeof...(Objectives)>::type());
91
92 }
93
95 return true;
96 }
97
99 for(auto& f: m_rotations){
100 SHARK_RUNTIME_CHECK(f.hasScalableDimensionality(),"Function is not scalable");
101 f.setNumberOfVariables(numberOfVariables);
102 }
103 }
104
105 std::size_t numberOfObjectives()const{
106 return sizeof...(Objectives);
107 }
108
109 std::size_t numberOfVariables()const{
110 return get<0>().numberOfVariables();
111 }
112
113 template<int N>
114 typename std::tuple_element<N, std::tuple<Objectives...> >::type& get(){
115 return std::get<N>(m_objectives);
116 }
117 template<int N>
118 typename std::tuple_element<N, std::tuple<Objectives...> >::type const& get()const{
119 return std::get<N>(m_objectives);
120 }
121
122 ///\ Initializes the functions as well as picks random rotations and translations
123 void init() {
124 m_translations.clear();
125
126 for(auto& f: m_rotations)
127 {
128 RealVector translation(numberOfVariables());
129 for(double& v: translation){
130 v=random::gauss(*mep_rng, 0,1)/std::sqrt(double(numberOfVariables()));
131 }
132 m_translations.push_back(translation);
133 f.setRng(mep_rng);
134 f.init();
135 }
136 }
137
139 RealVector x(numberOfVariables());
140
141 std::size_t index = random::discrete(0,m_rotations.size()-1);
142 for (std::size_t i = 0; i < x.size(); i++) {
143 x(i) = m_translations[index](i)+random::gauss(*mep_rng, 0,1)/std::sqrt(double(numberOfVariables()));
144 }
145 return x;
146 }
147
148 /// Returns the vector (f_1(x),...,f_N(x)) of the N objectives in the benchmark for the current point.
149 ResultType eval( SearchPointType const& x ) const {
151
153 for(std::size_t i = 0; i != value.size(); ++i){
154 value(i) = m_rotations[i].eval( x - m_translations[i]);
155 }
156 return value;
157 }
158 /// 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.
160 derivative.resize(numberOfObjectives(), numberOfVariables());
161 RealVector singleDerivative;
162 RealVector value(numberOfObjectives());
163 for(std::size_t i = 0; i != value.size(); ++i){
164 value(i) = m_rotations[i].evalDerivative( x - m_translations[i],singleDerivative);
165 noalias(row(derivative,i)) = singleDerivative;
166 }
167
168 return value;
169 }
170private:
171 //generate a rotated objective function for each function in the m_objectives tuple
172 template<int ... I>
173 void setupRotations(detail::integer_sequence<I...>){
174 m_rotations.insert(m_rotations.begin(), {RotatedObjectiveFunction(&std::get<I>(m_objectives))... });
175 }
176
177 template<int ... I>
178 std::string generateName(detail::integer_sequence<I...>)const{
179 std::string name;
180 for(auto const& fname:{std::get<I>(m_objectives).name()... }){
181 name+=fname+'/';
182 }
183 name.pop_back();
184 return name;
185 }
186
187 std::tuple<Objectives...> m_objectives;
188 std::vector<RotatedObjectiveFunction> m_rotations;
189 std::vector<RealVector> m_translations;
190};
191
192
193}}
194#endif