search.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #include "search.h"
  2. #include <cmath>
  3. #include <cassert>
  4. #include <algorithm> // sort
  5. #include <tuple> // tie, ignore
  6. using namespace std;
  7. /********************** search ***********************/
  8. search::search(int dim, int npoints, int *p) : dim(dim), npoints(npoints),
  9. best(1.), ha(dim, p), ps(dim, npoints) {
  10. assert(dim > 0);
  11. assert(npoints > 0);
  12. }
  13. void search::check() {
  14. current = ps.discrepancy();
  15. if(current < best) {
  16. best = current;
  17. FILE *f = fopen(filename.c_str(), "w");
  18. ps.dump(f);
  19. fclose(f);
  20. }
  21. }
  22. double search::run(int iterations) {
  23. _run(iterations);
  24. fprintf(stderr,"Best discrepancy found after %d iterations : %g\nResult saved in %s\n", iterations, best, filename.c_str());
  25. printf("%g\n", best);
  26. return best;
  27. }
  28. // compute points
  29. void search::compute() {
  30. for(int i = 0; i < npoints; i++)
  31. ha.compute(i+1, ps.point(i));
  32. }
  33. /********************** random_search ***********************/
  34. random_search::random_search(int dim, int npoints, int *p) : search(dim, npoints, p) {
  35. filename = std::string("random_search");
  36. }
  37. void random_search::_run(int iterations) {
  38. for(int t = 0; t < iterations; t++) {
  39. // shuffle permutations
  40. for(int i = 0; i < dim; i++)
  41. ha.get_pi(i).random();
  42. // compute points
  43. compute();
  44. // compute discrepancy and check if it is good
  45. check();
  46. }
  47. }
  48. /********************** local_search ***********************/
  49. local_search::local_search(int dim, int npoints, int *p) : search(dim, npoints, p),
  50. undoable(false) {
  51. }
  52. void local_search::init() {
  53. // random initial configuration
  54. for(int i = 0; i < dim; i++)
  55. ha.get_pi(i).random();
  56. compute();
  57. check();
  58. }
  59. void local_search::random_neighbour() {
  60. undoable = true;
  61. _random_neighbour();
  62. }
  63. void local_search::_random_neighbour() {
  64. i = rand()%dim;
  65. int p = ha.get_p(i);
  66. t1 = 1+rand()%(p-1);
  67. t2 = 1+rand()%(p-2);
  68. // ensure t1 != t2
  69. if(t2 >= t1)
  70. t2++;
  71. ha.get_pi(i).transpose(t1, t2);
  72. }
  73. void local_search::undo() {
  74. assert(undoable);
  75. undoable = false;
  76. _undo();
  77. }
  78. void local_search::_undo() {
  79. ha.get_pi(i).transpose(t1, t2);
  80. }
  81. void local_search::_run(int iterations) {
  82. for(int t = 0; t < iterations; t++) {
  83. previous = current;
  84. random_neighbour();
  85. compute();
  86. check();
  87. if(!accept(previous, current)) {
  88. current = previous;
  89. undo();
  90. }
  91. }
  92. }
  93. /********************** random_local_search ***********************/
  94. random_local_search::random_local_search(int dim, int npoints, int *p)
  95. :local_search(dim, npoints, p) {
  96. filename = std::string("random_local_search");
  97. init();
  98. }
  99. bool random_local_search::accept(double previous, double current) {
  100. return current < previous;
  101. }
  102. /********************** sa_local_search ***********************/
  103. sa_local_search::sa_local_search(int dim, int npoints, int *p, double lambda, double temp)
  104. :local_search(dim, npoints, p), lambda(lambda), temp(temp) {
  105. assert(0 <= lambda && lambda < 1);
  106. filename = std::string("sa_local_search_") + std::to_string(lambda);
  107. init();
  108. }
  109. bool sa_local_search::accept(double previous, double current) {
  110. if(current < previous)
  111. temp *= lambda;
  112. //printf("%lf\t%lf\n", temp, current);
  113. return current < previous || (double)rand()/RAND_MAX < exp((previous - current)/temp);
  114. }
  115. /********************** genetic_search ***********************/
  116. genetic_search::genetic_search(int dim, int npoints, int *p, int mu, int lambda, double c) :
  117. search(dim, npoints, p), mu(mu), lambda(lambda), c(c) {
  118. assert(mu > 0);
  119. assert(lambda > 0);
  120. assert(0 <= c && c <= 1);
  121. filename = std::string("genetic_search_") + std::to_string(mu)
  122. + "_" + std::to_string(lambda)
  123. + "_" + std::to_string(c);
  124. //init(); // not necessary here
  125. genes.reserve(mu+lambda);
  126. vector<permutation> base;
  127. // basic vector of permutations
  128. base.reserve(dim);
  129. for(int i = 0; i < dim; i++)
  130. base.emplace_back(p[i]);
  131. // generate mu random genes
  132. for(int i = 0; i < mu; i++) {
  133. genes.push_back(make_pair(1., base));
  134. for(int j = 0; j < dim; j++)
  135. genes[i].second[j].random();
  136. }
  137. // "reserve" lambda other genes (later we'll only change permutations already
  138. // created here)
  139. for(int i = 0; i < lambda; i++)
  140. genes.push_back(make_pair(1., base));
  141. }
  142. bool genes_ord(pair<double, vector<permutation>> &a, pair<double, vector<permutation>> &b) {
  143. return a.first < b.first;
  144. }
  145. void genetic_search::_run(int iterations) {
  146. for(int t = 0; t < iterations; t++) {
  147. // generate lambda new genes
  148. for(int i = 0; i < lambda; i++) {
  149. vector<permutation> &gene = genes[mu+i].second;
  150. if((double)rand()/RAND_MAX < c) {
  151. // crossover
  152. int g1 = rand()%mu, g2 = rand()%mu;
  153. for(int d = 0; d < dim; d++)
  154. gene[d] = permutation_crossover(genes[g1].second[d], genes[g2].second[d]);
  155. }
  156. else {
  157. // mutation from a gene
  158. gene = genes[rand()%mu].second;
  159. int id = rand()%dim;
  160. int p = ha.get_p(id);
  161. int t1 = 1+rand()%(p-1), t2 = 1+rand()%(p-2);
  162. // ensure t1 != t2
  163. if(t2 >= t1)
  164. t2++;
  165. gene[id].transpose(t1, t2);
  166. }
  167. }
  168. // for all gene
  169. for(int i = 0; i < mu+lambda; i++) {
  170. // replace permutations
  171. // compute points
  172. ha.set_pis(genes[i].second);
  173. compute();
  174. // compute discrepancy and check if it is good
  175. check();
  176. genes[i].first = current;
  177. }
  178. // sort genes : we want the mu firsts at the beginning
  179. sort(genes.begin(), genes.end(), genes_ord);
  180. }
  181. }