PaGMO  1.1.5
firefly.cpp
1 /*****************************************************************************
2  * Copyright (C) 2004-2015 The PaGMO development team, *
3  * Advanced Concepts Team (ACT), European Space Agency (ESA) *
4  * *
5  * https://github.com/esa/pagmo *
6  * *
7  * act@esa.int *
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  * This program is distributed in the hope that it will be useful, *
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17  * GNU General Public License for more details. *
18  * *
19  * You should have received a copy of the GNU General Public License *
20  * along with this program; if not, write to the *
21  * Free Software Foundation, Inc., *
22  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
23  *****************************************************************************/
24 
25 #include <string>
26 #include <vector>
27 #include <boost/random/uniform_int.hpp>
28 #include <boost/random/uniform_real.hpp>
29 
30 #include "firefly.h"
31 #include "../exceptions.h"
32 #include "../population.h"
33 #include "../problem/base.h"
34 #include "../types.h"
35 
36 
37 
38 
39 namespace pagmo { namespace algorithm {
40 
42 
51 firefly::firefly(int gen, double alpha, double beta, double gamma):base(),m_iter(gen), m_alpha(alpha), m_beta(beta), m_gamma(gamma) {
52  if (gen < 0) {
53  pagmo_throw(value_error,"number of iterations must be nonnegative");
54  }
55  if (alpha < 0 || alpha > 1) {
56  pagmo_throw(value_error,"alpha should be in [0,1]");
57  }
58  if (beta < 0 || beta > 1) {
59  pagmo_throw(value_error,"beta should be in [0,1]");
60  }
61  if (gamma < 0 || gamma > 1) {
62  pagmo_throw(value_error,"gamma should be in [0,1] interval");
63  }
64 }
65 
68 {
69  return base_ptr(new firefly(*this));
70 }
71 
73 
78 void firefly::evolve(population &pop) const
79 {
80  // Let's store some useful variables.
81  const problem::base &prob = pop.problem();
82  const problem::base::size_type prob_i_dimension = prob.get_i_dimension(), D = prob.get_dimension(), Dc = D - prob_i_dimension, prob_c_dimension = prob.get_c_dimension();
83  const decision_vector &lb = prob.get_lb(), &ub = prob.get_ub();
84  const population::size_type NP = (int) pop.size();
85 
86  //We perform some checks to determine whether the problem/population are suitable for Firefly
87  if ( Dc == 0 ) {
88  pagmo_throw(value_error,"There is no continuous part in the problem decision vector for Firefly to optimise");
89  }
90 
91  if ( prob.get_f_dimension() != 1 ) {
92  pagmo_throw(value_error,"The problem is not single objective and Firefly is not suitable to solve it");
93  }
94 
95  if ( prob_c_dimension != 0 ) {
96  pagmo_throw(value_error,"The problem is not box constrained and Firefly is not suitable to solve it");
97  }
98 
99  if (NP < 2) {
100  pagmo_throw(value_error,"for Firefly at least 2 individuals in the population are needed");
101  }
102 
103  // Get out if there is nothing to do.
104  if (m_iter == 0) {
105  return;
106  }
107 
108  // Some vectors used during evolution are allocated here.
109  decision_vector dummy(D,0); //used for initialisation purposes
110  std::vector<decision_vector> X(NP,dummy); //set of firefly positions
111  std::vector<decision_vector> X0(NP,dummy); //set of firefly positions kept to calculate velocity
112  std::vector<fitness_vector> fit(NP); //set of firefly positions fitness
113 
114  // Copy the fireflies position and their fitness
115  for ( population::size_type i = 0; i<NP; i++ ) {
116  X[i] = pop.get_individual(i).cur_x;
117  fit[i] = pop.get_individual(i).cur_f;
118  X0[i] = pop.get_individual(i).cur_x;
119  }
120 
121  double gamma_nominal_distance = 16.0; // factor comes from scaling r_sqrd by r_max_sqrd in attractiveness calculation (applies a nominal distance)
122  double newgamma = gamma_nominal_distance * m_gamma;
123 
124  // Main Firefly loop
125  for (int j = 0; j < m_iter; ++j) {
126 
127  //Find maximum distance between individuals
128  double r_max_sqrd = 0;
129  for (population::size_type ii = 0; ii< NP; ++ii) {
130  for (population::size_type jj = ii+1; jj< NP; ++jj) {
131  double r_temp_sqrd = 0;
132  for(problem::base::size_type k=0; k < Dc; ++k) {
133  r_temp_sqrd += (X[ii][k] - X[jj][k])*(X[ii][k]-X[jj][k]);
134  }
135  if (r_temp_sqrd > r_max_sqrd) {
136  r_max_sqrd = r_temp_sqrd;
137  }
138  }
139  }
140 
141  bool moveIItoJJ;
142  double r_sqrd; //temp variable to store distances squared between fireflies
143  double b; //temp variable to store attractiveness of a firefly
144  decision_vector X_start;
145  fitness_vector test_fit = fit[0];
146  for (population::size_type ii = 0; ii< NP; ++ii) {
147  for (population::size_type jj = 0; jj< NP; ++jj) {
148  moveIItoJJ = prob.compare_fitness(fit[jj], fit[ii]); //if jj is better than ii
149  if(moveIItoJJ) {
150 
151  //Calculate distance between X[ii] and X[jj]
152  r_sqrd = 0;
153  for(problem::base::size_type k=0; k < Dc; ++k) {
154  r_sqrd += (X[ii][k] - X[jj][k]) * (X[ii][k] - X[jj][k]) ;
155  }
156 
157  b = m_beta * exp( -1 * newgamma * sqrt(r_sqrd/r_max_sqrd)); //calculate attractiveness
158 
159  //Move the firefly ii torwards jj
160  for(problem::base::size_type k=0; k < Dc; ++k) {
161  X[ii][k] = (1-b) * X[ii][k] + b * X[jj][k];
162  }
163  }
164  else {
165  X_start = X[ii];
166  }
167 
168  // always apply random walk and check bounds
169  for(problem::base::size_type k = 0; k< Dc; ++k) {
170  X[ii][k] += boost::uniform_real<double>(-m_alpha, m_alpha)(m_drng) * (ub[k] - lb[k]);
171 
172  //check constraints
173  if (X[ii][k] < lb[k]) {
174  X[ii][k] = lb[k];
175  }
176  else if (X[ii][k] > ub[k]) {
177  X[ii][k] = ub[k];
178  }
179 
180  }
181 
182  prob.objfun(test_fit, X[ii]);
183  if(moveIItoJJ || prob.compare_fitness(test_fit, fit[ii])) { // only if moving ii towards jj or if new location has better fitness, update population and fitness
184  pop.set_x(ii, X[ii]);
185  fit[ii] = test_fit;
186  }
187  else {
188  X[ii] = X_start;
189  }
190  }
191 
192  }
193  } // end of main Firefly loop
194  for (population::size_type i = 0; i< NP; ++i) {
195  std::transform(X[i].begin(), X[i].end(), X0[i].begin(), dummy.begin(), std::minus<double>()); // dummy is now velocity for i-th individual
196  pop.set_v(i, dummy);
197  }
198 
199 }
200 
202 std::string firefly::get_name() const
203 {
204  return "Firefly optimization";
205 }
206 
207 
209 
212 std::string firefly::human_readable_extra() const
213 {
214  std::ostringstream s;
215  s << "iter:" << m_iter << ' ';
216  s << "alpha:" << m_alpha << ' ';
217  s << "beta:" << m_beta << ' ';
218  s << "gamma:" << m_gamma << ' ';
219  return s.str();
220 }
221 
222 }} //namespaces
223 
224 BOOST_CLASS_EXPORT_IMPLEMENT(pagmo::algorithm::firefly)
boost::shared_ptr< base > base_ptr
Alias for shared pointer to base algorithm.
Root PaGMO namespace.
std::vector< double > decision_vector
Decision vector type.
Definition: types.h:40
std::string get_name() const
Algorithm name.
Definition: firefly.cpp:202
fitness_vector cur_f
Current fitness vector.
Definition: population.h:89
const individual_type & get_individual(const size_type &) const
Get constant reference to individual at position n.
Definition: population.cpp:277
std::string human_readable_extra() const
Extra human readable algorithm info.
Definition: firefly.cpp:212
The Firefly algorithm.
Definition: firefly.h:60
Base algorithm class.
void evolve(population &) const
Evolve implementation.
Definition: firefly.cpp:78
Base problem class.
Definition: problem/base.h:148
Population class.
Definition: population.h:70
size_type get_dimension() const
Return global dimension.
bool compare_fitness(const fitness_vector &, const fitness_vector &) const
Compare fitness vectors.
fitness_vector objfun(const decision_vector &) const
Return fitness of pagmo::decision_vector.
size_type get_i_dimension() const
Return integer dimension.
std::vector< double > fitness_vector
Fitness vector type.
Definition: types.h:42
c_size_type get_c_dimension() const
Return global constraints dimension.
const decision_vector & get_ub() const
Upper bounds getter.
container_type::size_type size_type
Population size type.
Definition: population.h:192
decision_vector cur_x
Current decision vector.
Definition: population.h:83
f_size_type get_f_dimension() const
Return fitness dimension.
firefly(int gen=1, double alpha=0.01, double beta=1.0, double gamma=0.8)
Constructor.
Definition: firefly.cpp:51
base_ptr clone() const
Clone method.
Definition: firefly.cpp:67
const decision_vector & get_lb() const
Lower bounds getter.
rng_double m_drng
Random number generator for double-precision floating point values.
decision_vector::size_type size_type
Problem's size type: the same as pagmo::decision_vector's size type.
Definition: problem/base.h:160