You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

204 lines
4.3 KiB

#include <assert.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "benchmark-data.h"
/* TODO: Use typedefs for solution and vector instead of using int (*s)[230]
* and double (*v)[42]. */
/* Functions */
double distance(const double (*u)[42], const double (*v)[42]);
bool trouver_solution_initiale(void);
bool solution_valide(int (*s)[230]);
void print_solution(int (*s)[230], const char *name);
void centre_gravite(int cluster, int (*s)[230], double (*cg)[42]);
int solution_voisine(int (*dest)[230], int (*src)[230]);
int solution[230] = {0};
int new_solution[230] = {0};
int n_clusters = 5;
int n_iterations = 1000;
int main(int argc, char *argv[])
{
int c;
int i;
while ((c = getopt(argc, argv, ":c:i:h")) != -1) {
int k;
switch (c) {
case 'c':
k = atoi(optarg);
if (k > 0)
n_clusters = k;
break;
case 'i':
k = atoi(optarg);
if (k > 0)
n_iterations = k;
break;
case 'h':
printf("Usage: %s [-c N_CLUSTERS] [-i N_ITERATIONS]", argv[0]);
exit(EXIT_SUCCESS);
break;
default:
exit(EXIT_FAILURE);
}
}
printf("Using %d clusters\n", n_clusters);
srand(time(NULL));
/* Solution initiale */
while (!trouver_solution_initiale())
continue; /* do it again */
print_solution(&solution, "initiale");
for (i = 0; i < n_iterations; i++) {
while (!solution_voisine(&new_solution, &solution))
continue; /* do it again */
/* TODO: Calculer les centres de gravités, les distances moyennes inter-/intra-cluster,
* et faire le reste de l'algorithme */
}
exit(EXIT_SUCCESS);
}
double distance(const double (*u)[42], const double (*v)[42])
{
size_t n = sizeof(*v) / sizeof((*v)[0]);
size_t i = 0;
double sum = 0.0;
printf("distance(): n = %zu\n", n);
/* d(u, v) = sqrt( (u1 - v1)^2 + (u2 - v2)^2 + ... + (un - vn)^2 ) */
for (; i < n; i++)
sum += pow((*u)[i] - (*v)[i], 2);
return sqrt(sum);
}
bool trouver_solution_initiale(void)
{
size_t i;
for (i = 0; i < sizeof(solution) / sizeof(solution[0]); i++)
solution[i] = rand() % n_clusters;
return solution_valide(&solution);
}
bool solution_valide(int (*s)[230])
{
/* This function returns true if the solution that it found is "valid",
* i.e., it has at least one element in each cluster. */
bool *cluster_empty = calloc(n_clusters, sizeof *cluster_empty);
bool valid = true;
int i;
for (i = 0; i < n_clusters; i++)
cluster_empty[i] = true;
for (i = 0; (size_t) i < sizeof(*s) / sizeof(*s[0]); i++)
cluster_empty[(*s)[i]] = false;
for (i = 0; valid && i < n_clusters; i++)
valid = (valid && !cluster_empty[i]);
free(cluster_empty);
return valid;
}
void print_solution(int (*s)[230], const char *name)
{
size_t i = 0, n = sizeof(*s) / sizeof((*s)[0]);
printf("Solution%s%s:\n[", name ? " " : "", name ? name : "");
while (i < n) {
const char *end;
if (i + 1 == n)
end = "]\n";
else if (i && i % 20 == 0)
end = ",\n";
else
end = ", ";
printf("%d%s", (*s)[i++], end);
}
}
void centre_gravite(int cluster, int (*s)[230], double (*cg)[42])
{
/* Calculer le centre de gravité pour les vecteurs du cluster cluster selon la solution s */
const size_t n = sizeof(*cg) / sizeof((*cg)[0]); /* nombre d'attributs dans chaque vecteur. n = 42 */
const size_t nv = sizeof(benchmark_data) / sizeof(benchmark_data[0]); /* nombre de vecteurs. nv = 230 */
size_t i = 0;
assert(n == 42);
assert(nv == 230);
/* Initialiser à 0 */
while (i < n)
(*cg)[i++] = 0;
/* Loop over all vectors */
for (i = 0; i < nv; i++) {
size_t j = 0;
if ((*s)[i] != cluster)
/* Vector i is not part of the cluster, skip it */
continue;
while (j < n)
(*cg)[j] += benchmark_data[i][j];
}
for (i = 0; i < n; i++) {
(*cg)[i] /= n;
}
}
int solution_voisine(int (*dest)[230], int (*src)[230])
{
/* This function changes about 10% of the solution randomly */
memcpy(*dest, *src, sizeof(*src));
const size_t n = sizeof(*src) / sizeof((*src)[0]);
size_t i;
const int a = 10000; /* b = 10% of a */
const int b = 1000;
assert(n == 230);
for (i = 0; i < n; i++) {
if (rand() % a < b) {
int new_cluster = rand() % (n_clusters - 1);
/* To avoid the case where the cluster isn't actually changed. */
new_cluster += (new_cluster >= (*src)[i]);
(*dest)[i] = new_cluster;
}
}
return solution_valide(dest);
}