/// @file /// @brief Task3: program with command line options /// @todo Include header from modules/iue-*, as needed /// e.g. #include "iue-po/cpo.h" /// e.g. #include "iue-io/ccsv.h" /// @todo Include header of task2, if needed // #include "task2.h" /// @todo Include C standard library headers, as needed /// e.g. #include // EXIT_FAILURE, EXIT_SUCCESS /// @todo Implement an executable program which the following top-level description: /// 1. reads two matrices 'L', and 'R' from two separate .csv-files /// 2. calculates the matrix product LR (i.e. a matrix-matrix multiplication) /// 3. stores the resulting matrix in a third .csv-file /// Detailed Requirements: /// 1. All .csv-files which are involved need to be compatible with /// the format supported by 'iueio_savetxt' and 'iueio_loadtxt' from the header 'iue-io/ccsv.h' /// using ';' as delimiter and '#' as comment /// 2. The program needs to support the following three mandatory command line arguments in arbitrary order: /// --left relative filepath to the 'L' matrix /// --right relative filepath to the 'R' matrix /// --out relative filepath for the produced result /// 3. The program prints an error message to stderr, terminates, and returns EXIT_FAILURE if /// a) If any of the mandatory arguments is missing /// b) If any of the provided filepaths is not valid /// c) If any of the provided files cannot be parsed successfully /// d) If the dimension of the provided matrices are not compatible /// 4. If the program finishes without any issue, it returns EXIT_SUCCESS /// /// Implementation hints/valid assumtions for this exercise: /// - you do not need to support empty .csv-files /// - you can always assume that all rows in a .csv-file have the same length /// @file /// @brief Task3: program with command line options #include "modules/iue-io/ccsv.h" #include #include #include #include #define DELIM ';' #define COMMENT '#' // Function to multiply two matrices double** multiply_matrices(double** L, size_t L_rows, size_t L_cols, double** R, size_t R_rows, size_t R_cols, size_t* out_rows, size_t* out_cols) { if (L_cols != R_rows) { return NULL; // Incompatible dimensions } *out_rows = L_rows; *out_cols = R_cols; double** result = malloc(L_rows * sizeof(double*)); for (size_t i = 0; i < L_rows; ++i) { result[i] = malloc(R_cols * sizeof(double)); for (size_t j = 0; j < R_cols; ++j) { result[i][j] = 0.0; for (size_t k = 0; k < L_cols; ++k) { result[i][j] += L[i][k] * R[k][j]; } } } return result; } int main(int argc, char* argv[]) { char* left_filepath = NULL; char* right_filepath = NULL; char* out_filepath = NULL; bool left_set = false; bool right_set = false; bool out_set = false; // Parse command line arguments for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "--left") == 0) { if (i + 1 >= argc) { fprintf(stderr, "Missing argument for --left\n"); return EXIT_FAILURE; } left_filepath = argv[i + 1]; left_set = true; i++; } else if (strcmp(argv[i], "--right") == 0) { if (i + 1 >= argc) { fprintf(stderr, "Missing argument for --right\n"); return EXIT_FAILURE; } right_filepath = argv[i + 1]; right_set = true; i++; } else if (strcmp(argv[i], "--out") == 0) { if (i + 1 >= argc) { fprintf(stderr, "Missing argument for --out\n"); return EXIT_FAILURE; } out_filepath = argv[i + 1]; out_set = true; i++; } } // Check for missing mandatory arguments if (!left_set || !right_set || !out_set) { fprintf(stderr, "Missing mandatory arguments. Usage: %s --left --right --out " "\n", argv[0]); return EXIT_FAILURE; } // Load matrices from files struct Table left_table = {NULL, 0}; struct Table right_table = {NULL, 0}; if (iueio_loadtxt(left_filepath, &left_table, DELIM, COMMENT) != 0) { fprintf(stderr, "Error loading file %s\n", left_filepath); return EXIT_FAILURE; } if (iueio_loadtxt(right_filepath, &right_table, DELIM, COMMENT) != 0) { fprintf(stderr, "Error loading file %s\n", right_filepath); return EXIT_FAILURE; } // Check if the matrices are compatible //if (left_table.n == 0 || right_table.n == 0 || left_table.rows[0].n != right_table.rows[0].n) { // fprintf(stderr, "Incompatible dimensions\n"); // return EXIT_FAILURE; //} // Convert tables to matrices size_t L_rows = left_table.n; size_t L_cols = left_table.rows[0].n; double** L = malloc(L_rows * sizeof(double*)); for (size_t i = 0; i < L_rows; ++i) { L[i] = malloc(L_cols * sizeof(double)); for (size_t j = 0; j < L_cols; ++j) { L[i][j] = left_table.rows[i].values[j]; } } size_t R_rows = right_table.n; size_t R_cols = right_table.rows[0].n; double** R = malloc(R_rows * sizeof(double*)); for (size_t i = 0; i < R_rows; ++i) { R[i] = malloc(R_cols * sizeof(double)); for (size_t j = 0; j < R_cols; ++j) { R[i][j] = right_table.rows[i].values[j]; } } // Multiply matrices size_t out_rows, out_cols; double** result = multiply_matrices(L, L_rows, L_cols, R, R_rows, R_cols, &out_rows, &out_cols); if (result == NULL) { fprintf(stderr, "Incompatible dimensions\n"); return EXIT_FAILURE; } // Convert result to table struct Table out_table = {NULL, 0}; for (size_t i = 0; i < out_rows; ++i) { table_append_copy(&out_table, result[i], out_cols); } // Save result to file if (iueio_savetxt(out_filepath, &out_table, DELIM, "", COMMENT) != 0) { fprintf(stderr, "Error saving file %s\n", out_filepath); return EXIT_FAILURE; } // Free memory for (size_t i = 0; i < L_rows; ++i) { free(L[i]); } free(L); for (size_t i = 0; i < R_rows; ++i) { free(R[i]); } free(R); for (size_t i = 0; i < out_rows; ++i) { free(result[i]); } free(result); table_clear(&left_table); table_clear(&right_table); table_clear(&out_table); return EXIT_SUCCESS; }