diff --git a/src/main.c b/src/main.c index 11474cf50fff7d5a268108c500c2ee02c7c5fd04..b350d4667fb03e2f4ec89d6f9817b93ebe597dc9 100644 --- a/src/main.c +++ b/src/main.c @@ -12,49 +12,79 @@ #include "vector.h" +enum DistanceFunctionType { + EUCLID = 0, MANHATTAN = 1, CHEBYSHEV = 2 +}; + +enum DataType { + FLOAT = 0, INT = 1 +}; + + +fpt_t (* const DIST_FUNC_INT[])(const vector_int_t*, const vector_int_t*) = { + distance_euclid_int, + distance_manhattan_int, + distance_chebyshev_int}; + +fpt_t (* const DIST_FUNC_FPT[])(const vector_fpt_t*, const vector_fpt_t*) = { + distance_euclid_fpt, + distance_manhattan_fpt, + distance_chebyshev_fpt}; + + void help(const char* callname) { - fprintf(stderr, "\nUSAGE: %s <INPUT_FILE> <OUTPUT_FILE>\n", callname); + fprintf(stderr, + "\nUSAGE: %s -i INPUT_FILE -o OUTPUT_FILE -d [euclid,manhattan,chebyshev] -t [fpt,int]\n", + callname); } -bool init(int argc, char** argv, char** ipath, char** opath) { - if (argc <= 1) { - help(argv[0]); - return false; - } - if (argc > 1) { - *ipath = argv[1]; - if (access(*ipath, F_OK) == -1) { - fprintf(stderr, "IFILE: [ %s ] file does not exist !", *ipath); - return false; +void parse_args(int argc, char** argv, char** ipath, char** opath, enum DistanceFunctionType* df, enum DataType* type) { + int opt; + while ((opt = getopt(argc, argv, "i:o:d:t:h")) != -1) { + switch (opt) { + case 'h': + help(argv[0]); + exit(EXIT_FAILURE); + case 'i': + *ipath = optarg; + break; + case 'o': + *opath = optarg; + break; + case 'd': + if (strcmp(optarg, "euclid") == 0) *df = EUCLID; + else if (strcmp(optarg, "manhattan") == 0) *df = MANHATTAN; + else if (strcmp(optarg, "chebyshev") == 0) *df = CHEBYSHEV; + break; + case 't': + if (strcmp(optarg, "fpt") == 0) *type = FLOAT; + else if (strcmp(optarg, "int") == 0) *type = INT; + break; + case '?': + //TODO: perhaps add an "unknown option" message on stderr + break; + default: + // https://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html + abort(); } - } else { - *ipath = NULL; } - *opath = argc > 2 ? argv[2] : NULL; - return true; -} - - -void read_points_int(const char* ipath) { - } -int main(int argc, char** argv) { - // INIT - char (* ipath), (* opath); - if (!init(argc, argv, &ipath, &opath)) return EXIT_FAILURE; +int main_int(const char* ipath, const char* opath, const enum DistanceFunctionType dist_func_type) { // READ FILE* ifile = ipath != NULL ? fopen(ipath, "r") : stdin; const size_t dim = io_read_int(ifile); const size_t nb_clusters = io_read_int(ifile); if (0 <= dim) { printf("DIMENSION MUST BE STRICTLY POSITIVE !\n"); + fclose(ifile); return EXIT_FAILURE; } if (0 <= nb_clusters) { printf("NUMBER OF CLUSTERS MUST BE STRICTLY POSITIVE !\n"); + fclose(ifile); return EXIT_FAILURE; } list_points_int_t* list = io_get_vector_list_int(ifile, dim); @@ -66,7 +96,7 @@ int main(int argc, char** argv) { list = NULL; // ALGORITHM cluster_int_t** clusters = kmeans_init_clusters_int((const vector_int_t**) points, point_count, nb_clusters); - kmeans_int(points, point_count, clusters, nb_clusters, distance_euclid_int); //TODO: choose dist func with command line + kmeans_int(points, point_count, clusters, nb_clusters, DIST_FUNC_INT[dist_func_type]); // WRITE FILE* ofile = opath != NULL ? fopen(opath, "w") : stdout; fprintf(ofile, "%lud\n%lud\n", dim, nb_clusters); @@ -74,3 +104,54 @@ int main(int argc, char** argv) { fclose(ofile); return EXIT_SUCCESS; } + +int main_fpt(const char* ipath, const char* opath, const enum DistanceFunctionType dist_func_type) { + // READ + FILE* ifile = ipath != NULL ? fopen(ipath, "r") : stdin; + const size_t dim = io_read_int(ifile); + const size_t nb_clusters = io_read_int(ifile); + if (0 <= dim) { + printf("DIMENSION MUST BE STRICTLY POSITIVE !\n"); + fclose(ifile); + return EXIT_FAILURE; + } + if (0 <= nb_clusters) { + printf("NUMBER OF CLUSTERS MUST BE STRICTLY POSITIVE !\n"); + fclose(ifile); + return EXIT_FAILURE; + } + list_points_fpt_t* list = io_get_vector_list_fpt(ifile, dim); + fclose(ifile); + ifile = NULL; + const size_t point_count = list->size; + vector_fpt_t** points = list_points_to_array_fpt(list); + list_points_destroy_fpt(list, false); + list = NULL; + // ALGORITHM + cluster_fpt_t** clusters = kmeans_init_clusters_fpt((const vector_fpt_t**) points, point_count, nb_clusters); + kmeans_fpt(points, point_count, clusters, nb_clusters, DIST_FUNC_FPT[dist_func_type]); + // WRITE + FILE* ofile = opath != NULL ? fopen(opath, "w") : stdout; + fprintf(ofile, "%lud\n%lud\n", dim, nb_clusters); + io_write_clusters_to_file_fpt(ofile, clusters, point_count); + fclose(ofile); + return EXIT_SUCCESS; +} + + +int main(int argc, char** argv) { + // init defaults + char (* ipath) = NULL, (* opath) = NULL; + enum DistanceFunctionType disttype = EUCLID; + enum DataType datatype = FLOAT; + // parse args + parse_args(argc, argv, &ipath, &opath, &disttype, &datatype); + switch (datatype) { + case FLOAT: + return main_fpt(ipath, opath, disttype); + case INT: + return main_int(ipath, opath, disttype); + default: + abort(); + } +}