197 lines
6.3 KiB
C
197 lines
6.3 KiB
C
/// @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 <stdlib.h> // 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
#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 <left_file.csv> --right <right_file.csv> --out "
|
|
"<output_file.csv>\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;
|
|
}
|
|
|
|
|