pso.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #include "pso.h"
  2. #include <cassert>
  3. #include <Eigen/StdVector>
  4. #include <vector>
  5. #include <iostream>
  6. template <
  7. typename Scalar,
  8. typename DerivedX,
  9. typename DerivedLB,
  10. typename DerivedUB>
  11. IGL_INLINE Scalar igl::pso(
  12. const std::function< Scalar (DerivedX &) > f,
  13. const Eigen::MatrixBase<DerivedLB> & LB,
  14. const Eigen::MatrixBase<DerivedUB> & UB,
  15. const int max_iters,
  16. const int population,
  17. DerivedX & X)
  18. {
  19. const Eigen::Array<bool,Eigen::Dynamic,1> P =
  20. Eigen::Array<bool,Eigen::Dynamic,1>::Zero(LB.size(),1);
  21. return igl::pso(f,LB,UB,P,max_iters,population,X);
  22. }
  23. template <
  24. typename Scalar,
  25. typename DerivedX,
  26. typename DerivedLB,
  27. typename DerivedUB,
  28. typename DerivedP>
  29. IGL_INLINE Scalar igl::pso(
  30. const std::function< Scalar (DerivedX &) > f,
  31. const Eigen::MatrixBase<DerivedLB> & LB,
  32. const Eigen::MatrixBase<DerivedUB> & UB,
  33. const Eigen::DenseBase<DerivedP> & P,
  34. const int max_iters,
  35. const int population,
  36. DerivedX & X)
  37. {
  38. const int dim = LB.size();
  39. assert(UB.size() == dim && "UB should match LB size");
  40. assert(P.size() == dim && "P should match LB size");
  41. typedef std::vector<DerivedX,Eigen::aligned_allocator<DerivedX> > VectorList;
  42. VectorList position(population);
  43. VectorList best_position(population);
  44. VectorList velocity(population);
  45. Eigen::Matrix<Scalar,Eigen::Dynamic,1> best_f(population);
  46. // https://en.wikipedia.org/wiki/Particle_swarm_optimization#Algorithm
  47. //
  48. // g → X
  49. // p_i → best[i]
  50. // v_i → velocity[i]
  51. // x_i → position[i]
  52. Scalar min_f = std::numeric_limits<Scalar>::max();
  53. for(int p=0;p<population;p++)
  54. {
  55. {
  56. const DerivedX R = DerivedX::Random(dim).array()*0.5+0.5;
  57. position[p] = LB.array() + R.array()*(UB-LB).array();
  58. }
  59. best_f[p] = f(position[p]);
  60. best_position[p] = position[p];
  61. if(best_f[p] < min_f)
  62. {
  63. min_f = best_f[p];
  64. X = best_position[p];
  65. }
  66. {
  67. const DerivedX R = DerivedX::Random(dim);
  68. velocity[p] = (UB-LB).array() * R.array();
  69. }
  70. }
  71. int iter = 0;
  72. Scalar omega = 0.98;
  73. Scalar phi_p = 0.01;
  74. Scalar phi_g = 0.01;
  75. while(true)
  76. {
  77. //if(iter % 10 == 0)
  78. //{
  79. // std::cout<<iter<<":"<<std::endl;
  80. // for(int p=0;p<population;p++)
  81. // {
  82. // std::cout<<" "<<best_f[p]<<", "<<best_position[p]<<std::endl;
  83. // }
  84. // std::cout<<std::endl;
  85. //}
  86. for(int p=0;p<population;p++)
  87. {
  88. const DerivedX R_p = DerivedX::Random(dim).array()*0.5+0.5;
  89. const DerivedX R_g = DerivedX::Random(dim).array()*0.5+0.5;
  90. velocity[p] =
  91. omega * velocity[p].array() +
  92. phi_p * R_p.array() *(best_position[p] - position[p]).array() +
  93. phi_g * R_g.array() *( X - position[p]).array();
  94. position[p] += velocity[p];
  95. // Clamp to bounds
  96. for(int d = 0;d<dim;d++)
  97. {
  98. //#define IGL_PSO_REFLECTION
  99. #ifdef IGL_PSO_REFLECTION
  100. assert(!P(d));
  101. // Reflect velocities if exceeding bounds
  102. if(position[p](d) < LB(d))
  103. {
  104. position[p](d) = LB(d);
  105. if(velocity[p](d) < 0.0) velocity[p](d) *= -1.0;
  106. }
  107. if(position[p](d) > UB(d))
  108. {
  109. position[p](d) = UB(d);
  110. if(velocity[p](d) > 0.0) velocity[p](d) *= -1.0;
  111. }
  112. #else
  113. //#warning "trying no bounds on periodic"
  114. // // TODO: I'm not sure this is the right thing to do/enough. The
  115. // // velocities could be weird. Suppose the current "best" value is ε and
  116. // // the value is -ε and the "periodic bounds" [0,2π]. Moding will send
  117. // // the value to 2π-ε but the "velocity" term will now be huge pointing
  118. // // all the way from 2π-ε to ε.
  119. // //
  120. // // Q: Would it be enough to try (all combinations) of ±(UB-LB) before
  121. // // computing velocities to "best"s? In the example above, instead of
  122. // //
  123. // // v += best - p = ε - (2π-ε) = -2π+2ε
  124. // //
  125. // // you'd use
  126. // //
  127. // // v += / argmin |b - p| \ - p = (ε+2π)-(2π-ε) = 2ε
  128. // // | |
  129. // // \ b∈{best, best+2π, best-2π} /
  130. // //
  131. // // Though, for multivariate b,p,v this would seem to explode
  132. // // combinatorially.
  133. // //
  134. // // Maybe periodic things just shouldn't be bounded and we hope that the
  135. // // forces toward the current minima "regularize" them away from insane
  136. // // values.
  137. // if(P(d))
  138. // {
  139. // position[p](d) = std::fmod(position[p](d)-LB(d),UB(d)-LB(d))+LB(d);
  140. // }else
  141. // {
  142. // position[p](d) = std::max(LB(d),std::min(UB(d),position[p](d)));
  143. // }
  144. position[p](d) = std::max(LB(d),std::min(UB(d),position[p](d)));
  145. #endif
  146. }
  147. const Scalar fp = f(position[p]);
  148. if(fp<best_f[p])
  149. {
  150. best_f[p] = fp;
  151. best_position[p] = position[p];
  152. if(best_f[p] < min_f)
  153. {
  154. min_f = best_f[p];
  155. X = best_position[p];
  156. }
  157. }
  158. }
  159. iter++;
  160. if(iter>=max_iters)
  161. {
  162. break;
  163. }
  164. }
  165. return min_f;
  166. }
  167. #ifdef IGL_STATIC_LIBRARY
  168. template float igl::pso<float, Eigen::Matrix<float, 1, -1, 1, 1, -1>, Eigen::Matrix<float, 1, -1, 1, 1, -1>, Eigen::Matrix<float, 1, -1, 1, 1, -1> >(std::function<float (Eigen::Matrix<float, 1, -1, 1, 1, -1>&)>, Eigen::MatrixBase<Eigen::Matrix<float, 1, -1, 1, 1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, -1, 1, 1, -1> > const&, int, int, Eigen::Matrix<float, 1, -1, 1, 1, -1>&);
  169. #endif