From 36576604878af86d8c79e2dfa7223cb80c2904b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20El=20Kharroubi?= <michael.el-kharroubi@etu.unige.ch> Date: Sun, 1 Nov 2020 23:18:22 +0100 Subject: [PATCH] Add comments --- C/main.c | 12 +++++++- C/vector.c | 68 +++++++++++++++++++++++++++++++++++----------- C/vector.h | 60 +++++++++++++++++++++++++++++++++------- Python/load_vec.py | 45 ++++++++++++++++++++++++++---- 4 files changed, 152 insertions(+), 33 deletions(-) diff --git a/C/main.c b/C/main.c index 2f8891a..e1a7fcf 100644 --- a/C/main.c +++ b/C/main.c @@ -3,20 +3,30 @@ #include "vector.h" +/** @brief + * An exemple of mathematical function + * in 1 dimension. + * + * @param x A double variable. + * @return f(x) = 2.0*sin(x) - 3.0*cos(x) + */ double my_function(double x) { - // 2.0*sin(x) - 3.0*cos(x) return 2.0 * sin(x) - 3.0 * cos(x); } int main() { + // Create a vector X = [0,1,2...99] double_vector_t *X = iota(100); + // Create a vector Y = my_function(x) double_vector_t *Y = apply_function(X, my_function); + // Export our vectors into files export_vector("../X.vec", X); export_vector("../Y.vec", Y); + // Free our vectors destroy_vector(&Y); destroy_vector(&X); } \ No newline at end of file diff --git a/C/vector.c b/C/vector.c index d8b58e8..431f1cf 100644 --- a/C/vector.c +++ b/C/vector.c @@ -3,7 +3,27 @@ #include "vector.h" -double_vector_t *init_vector(uint_t N) +/** @brief + * Compute the endianness used by + * the architecture. + * + * @return 1 if little-endian, 0 if big-endian + */ +uint8_t get_endianness() +{ + uint32_t endianness = 0x01020304; + // Return the endianness by accessing the first byte in memory + // which should be 1 if big-endian and 4 if little-endian + return *((uint8_t *)(&endianness)) == 4; +} + +/** @brief + * Create a vector of a given dimension. + * + * @param N The number of dimensions. + * @return A dynamically allocated vector + */ +double_vector_t *init_vector(uint32_t N) { double_vector_t *vec = malloc(sizeof(double_vector_t)); vec->components = malloc(N * sizeof(double)); @@ -15,40 +35,52 @@ double_vector_t *init_vector(uint_t N) } return vec; } -double_vector_t *iota(uint_t N) +/** @brief + * Create a vector of a given dimension, + * with values from 0 to N excluded. + * + * @param N The number of dimensions. + * @return A dynamically allocated vector : [0,1..N] + */ +double_vector_t *iota(uint32_t N) { double_vector_t *vec = init_vector(N); - for (uint_t i = 0; i < N; i++) + for (uint32_t i = 0; i < N; i++) { vec->components[i] = i; } return vec; } +/** @brief + * Apply a 1d function element-wise + * to a given vector, and return the + * result in a new vector. + * + * @param vec The argument vector + * @param f The 1d function to apply + * @return A dynamically allocated vector : f(X) + */ double_vector_t *apply_function(double_vector_t *vec, double_function_t f) { double_vector_t *res = init_vector(vec->N); - for (uint_t i = 0; i < vec->N; i++) + for (uint32_t i = 0; i < vec->N; i++) { res->components[i] = f(vec->components[i]); } return res; } -void fill_vector(double_vector_t *vec, double value) -{ - for (uint_t i = 0; i < vec->N; i++) - { - vec->components[i] = value; - } -} +/** @brief + * Export a vector into a file. + * + * @param filename The name of the output file + * @param vec The vector to export + */ void export_vector(const char *filename, double_vector_t *vec) { FILE *output = fopen(filename, "w"); - uint_t endianness = 0x01020304; vector_metadata_t metadata; - // Return the endianness by accessing the first byte in memory - // which should be 1 if big-endian and 4 if little-endian - metadata.endianness = *((byte_t *)(&endianness)) == 4; + metadata.endianness = get_endianness(); metadata.size_of_a_component = sizeof(double); metadata.number_of_component = vec->N; @@ -60,7 +92,11 @@ void export_vector(const char *filename, double_vector_t *vec) fclose(output); } - +/** @brief + * Free a vector. + * + * @param vec A double pointer on a vector + */ void destroy_vector(double_vector_t **vec) { free((*vec)->components); diff --git a/C/vector.h b/C/vector.h index 04a80e0..4b391f4 100644 --- a/C/vector.h +++ b/C/vector.h @@ -1,22 +1,62 @@ -typedef unsigned int uint_t; -typedef unsigned char byte_t; +#include <stdint.h> + typedef struct double_vector { - uint_t N; + uint32_t N; // The dimmension of the vector double *components; } double_vector_t; +// Function pointer, example : double f(double x); typedef double (*double_function_t)(double); +/* +* The attribute "packed" tells the compiler, +* that the struct should be stored in memory +* without padding. It's highly recommended, +* if we want to serialize the structure. +* (for example to store it in a file) +*/ typedef struct vector_metadata { - byte_t endianness; // 1 = little, 0 = big - byte_t size_of_a_component; // in bytes - uint_t number_of_component; + uint8_t endianness; // 1 = little, 0 = big + uint8_t size_of_a_component; // in bytes + uint32_t number_of_component; } __attribute__((packed)) vector_metadata_t; -double_vector_t *init_vector(uint_t N); -double_vector_t *iota(uint_t N); +/** @brief + * Create a vector of a given dimension. + * + * @param N The number of dimensions. + * @return A dynamically allocated vector + */ +double_vector_t *init_vector(uint32_t N); +/** @brief + * Create a vector of a given dimension, + * with values from 0 to N excluded. + * + * @param N The number of dimensions. + * @return A dynamically allocated vector : [0,1..N] + */ +double_vector_t *iota(uint32_t N); +/** @brief + * Apply a 1d function element-wise + * to a given vector, and return the + * result in a new vector. + * + * @param vec The argument vector + * @param f The 1d function to apply + * @return A dynamically allocated vector : f(X) + */ double_vector_t *apply_function(double_vector_t *vec, double_function_t f); -void fill_vector(double_vector_t *vec, double value); -void export_vector(const char *file, double_vector_t *vec); +/** @brief + * Export a vector into a file. + * + * @param filename The name of the output file + * @param vec The vector to export + */ +void export_vector(const char *filename, double_vector_t *vec); +/** @brief + * Free a vector. + * + * @param vec A double pointer on a vector + */ void destroy_vector(double_vector_t **vec); \ No newline at end of file diff --git a/Python/load_vec.py b/Python/load_vec.py index 400f85c..70b5d5f 100644 --- a/Python/load_vec.py +++ b/Python/load_vec.py @@ -1,16 +1,49 @@ import numpy as np +from typing import Tuple +METADATA_SIZE = 6 + + +def _parse_metada(metadata: bytes) -> Tuple[type, int]: + """ + Parse the metadata for a vec file. + + Parameters: + metadata (bytes): The metadata bytes + + Returns: + (type, int): The type and the number of component of the vector + """ + + little_endian = bool(metadata[0]) + endianness = 'little' if little_endian else 'big' + + size_of_components = int(metadata[1]) + # For now we only consider two types + datatype = np.float64 if size_of_components == 8 else np.float + + # Recover our 32 bit integer specifying the endianness + nb_components = int.from_bytes(metadata[2:], endianness) + + return datatype, nb_components def load_vector(filename: str) -> np.ndarray: + """ + Load a vector from a file. + + Parameters: + filename (str): The name of the file containing the vector + + Returns: + np.ndarray: The vector + + """ file = open(filename, 'rb') - header = file.read(6) + # Read our metadata struct + metadata = file.read(METADATA_SIZE) - little_endian = bool(header[0]) - size_of_components = int(header[1]) - nb_components = int.from_bytes( - header[2:], 'little' if little_endian else 'big') + datatype, nb_components = _parse_metada(metadata) - datatype = np.float64 if size_of_components == 8 else np.float array = np.fromfile(file, dtype=datatype, count=nb_components) file.close() -- GitLab