TU-Programmieren_2/exercise10/task3.main.c
2025-04-09 10:22:44 +02:00

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;
}