Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

main.c 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. #include <assert.h>
  2. #include <math.h>
  3. #include <stdbool.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <time.h>
  8. #include <unistd.h>
  9. #include "benchmark-data.h"
  10. /* Types */
  11. typedef int *solution;
  12. /* Functions */
  13. double distance(const vector u, const vector v);
  14. bool trouver_solution_initiale(void);
  15. bool solution_valide(const solution s);
  16. void print_solution(const solution s, const char *name);
  17. vector *centres_gravite(const solution s);
  18. int solution_voisine(solution *dest, const solution src);
  19. double fonction_objective(const solution s);
  20. static double calculer_inter(const vector *cgs);
  21. static double calculer_intra(const solution s, const vector *cgs);
  22. /* Variables */
  23. solution solution_opt;
  24. solution new_solution;
  25. int n_clusters = 5;
  26. int n_iterations = 1000;
  27. int main(int argc, char *argv[])
  28. {
  29. int c;
  30. int i;
  31. double f0;
  32. while ((c = getopt(argc, argv, ":c:i:h")) != -1) {
  33. int k;
  34. switch (c) {
  35. case 'c':
  36. k = atoi(optarg);
  37. if (k > 1)
  38. n_clusters = k;
  39. break;
  40. case 'i':
  41. k = atoi(optarg);
  42. if (k > 0)
  43. n_iterations = k;
  44. break;
  45. case 'h':
  46. printf("Usage: %s [-c N_CLUSTERS] [-i N_ITERATIONS]", argv[0]);
  47. exit(EXIT_SUCCESS);
  48. break;
  49. default:
  50. exit(EXIT_FAILURE);
  51. }
  52. }
  53. printf("Using %d clusters\n", n_clusters);
  54. /* Init benchmark_data */
  55. init_benchmark_data();
  56. srand(time(NULL));
  57. if (!(solution_opt = calloc(N_VECTORS, sizeof(solution_opt[0]))))
  58. abort();
  59. /* Solution initiale */
  60. while (!trouver_solution_initiale())
  61. continue; /* do it again */
  62. f0 = fonction_objective(solution_opt);
  63. print_solution(solution_opt, "initiale");
  64. printf("F(solution) = %f\n", f0);
  65. for (i = 0; i < n_iterations; i++) {
  66. double f1;
  67. while (!solution_voisine(&new_solution, solution_opt))
  68. continue; /* do it again */
  69. if ((f1 = fonction_objective(new_solution)) > f0) {
  70. print_solution(new_solution, "optimale trouvée");
  71. printf("F(solution) = %f (%f%% improvement)\n", f1, fabs((f1 - f0) / f0 * 100.0));
  72. free(solution_opt);
  73. solution_opt = new_solution;
  74. new_solution = NULL;
  75. f0 = f1;
  76. }
  77. }
  78. /* Free solution data */
  79. free(solution_opt);
  80. free(new_solution);
  81. /* Free benchmark data */
  82. for (i = 0; i < (int) N_VECTORS; i++)
  83. free(benchmark_data[i]);
  84. free(benchmark_data);
  85. exit(EXIT_SUCCESS);
  86. }
  87. double distance(const vector u, const vector v)
  88. {
  89. size_t i = 0;
  90. double sum = 0.0;
  91. if (!u || !v) {
  92. fputs("distance(): u or v is null.\n", stderr);
  93. abort();
  94. }
  95. /* d(u, v) = sqrt( (u1 - v1)^2 + (u2 - v2)^2 + ... + (un - vn)^2 ) */
  96. for (; i < VECTOR_SIZE; i++)
  97. sum += pow(u[i] - v[i], 2);
  98. return sqrt(sum);
  99. }
  100. bool trouver_solution_initiale(void)
  101. {
  102. size_t i;
  103. for (i = 0; i < N_VECTORS; i++)
  104. solution_opt[i] = rand() % n_clusters;
  105. return solution_valide(solution_opt);
  106. }
  107. bool solution_valide(const solution s)
  108. {
  109. /* This function returns true if the solution that it found is "valid",
  110. * i.e., it has at least one element in each cluster. */
  111. bool *cluster_empty = calloc(n_clusters, sizeof *cluster_empty);
  112. bool valid = true;
  113. int i;
  114. for (i = 0; i < n_clusters; i++)
  115. cluster_empty[i] = true;
  116. for (i = 0; (size_t) i < N_VECTORS; i++)
  117. cluster_empty[s[i]] = false;
  118. for (i = 0; valid && i < n_clusters; i++)
  119. valid = (valid && !cluster_empty[i]);
  120. free(cluster_empty);
  121. return valid;
  122. }
  123. void print_solution(const solution s, const char *name)
  124. {
  125. size_t i = 0;
  126. printf("Solution%s%s: [\n", name ? " " : "", name ? name : "");
  127. while (i < N_VECTORS) {
  128. const char *end;
  129. if (i + 1 == N_VECTORS)
  130. end = "]\n";
  131. else if ((i + 1) % 20 == 0)
  132. end = ",\n";
  133. else
  134. end = ", ";
  135. printf("%d%s", s[i++], end);
  136. }
  137. }
  138. vector *centres_gravite(const solution s)
  139. {
  140. /* Calculer le centre de gravité pour les vecteurs du cluster cluster selon la solution s */
  141. int cluster;
  142. size_t i = 0;
  143. /* cgs[n_clusters] est le centre de gravité global */
  144. vector *cgs = calloc(n_clusters + 1, sizeof(*cgs));
  145. int *vectors_in_cluster = calloc(n_clusters + 1, sizeof(*vectors_in_cluster));
  146. if (!cgs || !vectors_in_cluster)
  147. abort();
  148. for (cluster = 0; cluster < n_clusters + 1; cluster++) {
  149. if (!(cgs[cluster] = calloc(VECTOR_SIZE, sizeof(*cgs[cluster]))))
  150. abort();
  151. /* Initialiser à 0 */
  152. while (i < VECTOR_SIZE)
  153. cgs[cluster][i++] = 0;
  154. if (cluster < n_clusters)
  155. vectors_in_cluster[cluster] = 0;
  156. }
  157. for (i = 0; i < N_VECTORS; i++) {
  158. size_t j;
  159. cluster = s[i];
  160. ++vectors_in_cluster[cluster];
  161. for (j = 0; j < VECTOR_SIZE; j++) {
  162. cgs[cluster][j] += benchmark_data[i][j];
  163. cgs[n_clusters][j] += benchmark_data[i][j];
  164. }
  165. }
  166. vectors_in_cluster[n_clusters] = N_VECTORS;
  167. for (cluster = 0; cluster < n_clusters + 1; cluster++)
  168. for (i = 0; i < VECTOR_SIZE; i++)
  169. cgs[cluster][i] /= (double) vectors_in_cluster[cluster];
  170. free(vectors_in_cluster);
  171. return cgs;
  172. }
  173. int solution_voisine(solution *dest, const solution src)
  174. {
  175. /* This function changes about 10% of the solution randomly */
  176. size_t i;
  177. const int a = 10000; /* b = 10% of a */
  178. const int b = 1000;
  179. bool valid;
  180. if (!(*dest = calloc(N_VECTORS, sizeof(**dest))))
  181. abort();
  182. memcpy(*dest, src, N_VECTORS * sizeof(*src));
  183. assert(n_clusters > 1);
  184. for (i = 0; i < N_VECTORS; i++) {
  185. if (rand() % a < b) {
  186. int new_cluster = rand() % (n_clusters - 1);
  187. /* To avoid the case where the cluster isn't actually changed. */
  188. new_cluster += (new_cluster >= src[i]);
  189. (*dest)[i] = new_cluster;
  190. }
  191. }
  192. if (!(valid = solution_valide(*dest))) {
  193. free(*dest);
  194. *dest = NULL;
  195. }
  196. return valid;
  197. }
  198. double fonction_objective(const solution s)
  199. {
  200. int i;
  201. double **cgs = centres_gravite(s);
  202. double inter;
  203. double intra;
  204. if (!cgs)
  205. abort();
  206. inter = calculer_inter(cgs);
  207. intra = calculer_intra(s, cgs);
  208. for (i = 0; i < n_clusters + 1; i++)
  209. free(cgs[i]);
  210. free(cgs);
  211. return inter - intra;
  212. }
  213. static double calculer_inter(const vector *cgs)
  214. {
  215. double inter = 0.0;
  216. int cluster;
  217. for (cluster = 0; cluster < n_clusters; cluster++)
  218. inter += distance(cgs[n_clusters], cgs[cluster]);
  219. return inter / (double) n_clusters;
  220. }
  221. static double calculer_intra(const solution s, const vector *cgs)
  222. {
  223. double intra = 0.0;
  224. int cluster;
  225. for (cluster = 0; cluster < n_clusters; cluster++) {
  226. double intra_for_this_cluster = 0.0;
  227. int vectors_in_this_cluster = 0;
  228. size_t i;
  229. for (i = 0; i < N_VECTORS; i++) {
  230. if (s[i] != cluster)
  231. continue;
  232. ++vectors_in_this_cluster;
  233. intra_for_this_cluster += distance(cgs[cluster], benchmark_data[i]);
  234. }
  235. intra += intra_for_this_cluster / (double) vectors_in_this_cluster;
  236. }
  237. return intra / (double) n_clusters;
  238. }