ReferenceVectorGuidedSelection.h
Go to the documentation of this file.
1//===========================================================================
2/*!
3 *
4 *
5 * \brief Implements the reference vector selection for RVEA
6 *
7 * \author Bjoern Bugge Grathwohl
8 * \date March 2017
9 *
10 * \par Copyright 1995-2017 Shark Development Team
11 *
12 * <BR><HR>
13 * This file is part of Shark.
14 * <https://shark-ml.github.io/Shark/>
15 *
16 * Shark is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU Lesser General Public License as published
18 * by the Free Software Foundation, either version 3 of the License, or
19 * (at your option) any later version.
20 *
21 * Shark is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU Lesser General Public License for more details.
25 *
26 * You should have received a copy of the GNU Lesser General Public License
27 * along with Shark. If not, see <http://www.gnu.org/licenses/>.
28 *
29 */
30//===========================================================================
31
32#ifndef SHARK_ALGORITHMS_DIRECT_SEARCH_OPERATORS_SELECTION_REFERENCE_VECTOR_GUIDED_SELECTION_H
33#define SHARK_ALGORITHMS_DIRECT_SEARCH_OPERATORS_SELECTION_REFERENCE_VECTOR_GUIDED_SELECTION_H
34
35#include <shark/LinAlg/Base.h>
37
38namespace shark {
39
40/**
41 * \brief Implements the reference vector selection for the RVEA algorithm.
42 *
43 * This selector uses a set of unit reference vectors to partition the search
44 * space by assigning to each reference vector the individual that is "closest"
45 * to it, as measured by the angle-penalized distance.
46 * See below paper for details:
47 * R. Cheng, Y. Jin, M. Olhofer, and B. Sendhoff, “A reference vector guided
48 * evolutionary algorithm for many-objective optimization,” IEEE Transactions on
49 * Evolutionary Computation, Vol 20, Issue 5, October 2016
50 * http://dx.doi.org/10.1109/TEVC.2016.2519378
51 */
52template <typename IndividualType>
54{
55 typedef std::set<std::size_t> bag_t;
56
57 /**
58 * \brief Select individuals by marking them as "selected".
59 *
60 * The selection operator requires the set of reference vectors, the set of
61 * least angles between reference vectors (the gammas), as well as the
62 * current iteration number.
63 */
65 std::vector<IndividualType> & population,
66 RealMatrix const & referenceVectors,
67 RealVector const & gammas,
68 std::size_t const curIteration)
69 {
70 if(population.empty())
71 {
72 return;
73 }
74 RealMatrix fitness = extractPopulationFitness(population);
75 SIZE_CHECK(fitness.size2() == referenceVectors.size2());
76 const std::size_t groupCount = referenceVectors.size1();
77 // Objective value translation
78 // line 4
79 const RealVector minFitness = minCol(fitness);
80 // line 5-7
81 fitness -= repeat(minFitness, fitness.size1());
82
83 // Population partition
84 // line 9-13
85 const RealMatrix cosA = cosAngles(fitness, referenceVectors);
86 const RealMatrix angles = acos(cosA);
87 // line 14-17
88 const std::vector<bag_t> subGroups = populationPartition(cosA);
89 SIZE_CHECK(subGroups.size() == groupCount);
90 // Elitism selection
91 for(auto & p : population)
92 {
93 p.selected() = false;
94 }
95 const double theta = fitness.size2()
96 * std::pow(static_cast<double>(curIteration) /
97 static_cast<double>(m_maxIters), m_alpha);
98 // line 25-28
99 for(std::size_t j = 0; j < groupCount; ++j)
100 {
101 if(subGroups[j].size() == 0)
102 {
103 continue;
104 }
105 std::size_t selected_idx = 0;
106 double min = 1e5;
107 for(std::size_t i : subGroups[j])
108 {
109 // Angle-penalized distance (APD) calculation
110 double apd = 1 + theta * angles(i, j) / gammas[j];
111 apd *= norm_2(row(fitness, i));
112 if(apd < min)
113 {
114 selected_idx = i;
115 min = apd;
116 }
117 }
118 population[selected_idx].selected() = true;
119 }
120 }
121
122 /**
123 * \brief Associates a population to a set of reference vectors.
124 *
125 * The parameter is an N-by-M matrix where N is the population size and M is
126 * the number of reference vectors. Entry (i,j) is the cosine of the angle
127 * between population i and reference vector j.
128 */
129 static std::vector<bag_t> populationPartition(
130 RealMatrix const & cosAngles)
131 {
132 std::vector<std::set<std::size_t>> subGroups(cosAngles.size2());
133 for(std::size_t i = 0; i < cosAngles.size1(); ++i)
134 {
135 const std::size_t k = std::distance(
136 row(cosAngles, i).begin(),
137 std::max_element(row(cosAngles, i).begin(),
138 row(cosAngles, i).end()));
139 subGroups[k].insert(i);
140 }
141 return subGroups;
142 }
143
144 static RealMatrix extractPopulationFitness(
145 std::vector<IndividualType> const & population)
146 {
147 RealMatrix fitness(population.size(),
148 population[0].unpenalizedFitness().size());
149 for(std::size_t i = 0; i < population.size(); ++i)
150 {
151 row(fitness, i) = population[i].unpenalizedFitness();
152 }
153 return fitness;
154 }
155
156 static RealVector minCol(RealMatrix const & m)
157 {
158 RealVector minColumns(m.size2());
159 for(std::size_t i = 0; i < m.size2(); ++i)
160 {
161 minColumns[i] = min(column(m, i));
162 }
163 return minColumns;
164 }
165
166 /**
167 * \brief Compute cosine of angles between all row vectors in two matrices.
168 */
169 static RealMatrix cosAngles(RealMatrix const & m1, RealMatrix const & m2)
170 {
171 RealMatrix c = prod(m1, trans(m2));
172 for(std::size_t i = 0; i < c.size1(); ++i)
173 {
174 row(c, i) /= norm_2(row(m1, i));
175 }
176 return c;
177 }
178
179 template <typename Archive>
180 void serialize(Archive & archive)
181 {
182 archive & BOOST_SERIALIZATION_NVP(m_alpha);
183 archive & BOOST_SERIALIZATION_NVP(m_maxIters);
184 }
185
186 double m_alpha;
187 std::size_t m_maxIters;
188};
189
190} // namespace shark
191
192#endif // SHARK_ALGORITHMS_DIRECT_SEARCH_OPERATORS_SELECTION_REFERENCE_VECTOR_GUIDED_SELECTION_H