diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index a79403a..603ec4d 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -9,7 +9,8 @@ "defines": [], "cStandard": "c17", "cppStandard": "gnu++17", - "intelliSenseMode": "linux-gcc-x64" + "intelliSenseMode": "linux-gcc-x64", + "configurationProvider": "ms-vscode.makefile-tools" } ], "version": 4 diff --git a/.vscode/settings.json b/.vscode/settings.json index 9d395b2..9efaf49 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,11 @@ { "files.associations": { "random_graph.h": "c", - "random_groups.h": "c" + "random_groups.h": "c", + "random_edge_weight.h": "c", + "rand_large.h": "c", + "stdint.h": "c", + "random_group_steiner.h": "c", + "random_vertex_weight.h": "c" } } \ No newline at end of file diff --git a/Makefile b/Makefile index 3046050..541e33a 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # Compiler and Flags CC = gcc -# CFLAGS = -Wall -Wextra -Iinclude -g -pg -CFLAGS = -O2 -march=native -DNDEBUG -Wall -Wextra -Werror -Iinclude -LDFLAGS = -lm +CFLAGS = -Wall -Wextra -Iinclude -g -pg -O0 +# CFLAGS = -O3 -march=native -DNDEBUG -Wall -Wextra -Werror -Iinclude -s -flto -fno-math-errno +LDFLAGS = -lm -flto # Directories SRC_DIR = src diff --git a/analysis b/analysis new file mode 100644 index 0000000..9060855 --- /dev/null +++ b/analysis @@ -0,0 +1,160 @@ +Flat profile: + +Each sample counts as 0.01 seconds. + % cumulative self self total + time seconds seconds calls s/call s/call name +100.07 3.36 3.36 2 1.68 1.68 random_connected_graph + 0.00 3.36 0.00 6 0.00 0.00 cmpInt + 0.00 3.36 0.00 3 0.00 0.00 generate_random_edge_weight + + % the percentage of the total running time of the +time program used by this function. + +cumulative a running sum of the number of seconds accounted + seconds for by this function and those listed above it. + + self the number of seconds accounted for by this +seconds function alone. This is the major sort for this + listing. + +calls the number of times this function was invoked, if + this function is profiled, else blank. + + self the average number of milliseconds spent in this +ms/call function per call, if this function is profiled, + else blank. + + total the average number of milliseconds spent in this +ms/call function and its descendents per call, if this + function is profiled, else blank. + +name the name of the function. This is the minor sort + for this listing. The index shows the location of + the function in the gprof listing. If the index is + in parenthesis it shows where it would appear in + the gprof listing if it were to be printed. + +Copyright (C) 2012-2023 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. + + Call graph (explanation follows) + + +granularity: each sample hit covers 2 byte(s) for 0.30% of 3.36 seconds + +index % time self children called name + 1.68 0.00 1/2 main [3] + 1.68 0.00 1/2 generate_random_group_steiner_instance [2] +[1] 100.0 3.36 0.00 2 random_connected_graph [1] + 0.00 0.00 6/6 cmpInt [4] + 0.00 0.00 3/3 generate_random_edge_weight [5] +----------------------------------------------- + +[2] 50.0 0.00 1.68 generate_random_group_steiner_instance [2] + 1.68 0.00 1/2 random_connected_graph [1] +----------------------------------------------- + +[3] 50.0 0.00 1.68 main [3] + 1.68 0.00 1/2 random_connected_graph [1] +----------------------------------------------- + 0.00 0.00 6/6 random_connected_graph [1] +[4] 0.0 0.00 0.00 6 cmpInt [4] +----------------------------------------------- + 0.00 0.00 3/3 random_connected_graph [1] +[5] 0.0 0.00 0.00 3 generate_random_edge_weight [5] +----------------------------------------------- + + This table describes the call tree of the program, and was sorted by + the total amount of time spent in each function and its children. + + Each entry in this table consists of several lines. The line with the + index number at the left hand margin lists the current function. + The lines above it list the functions that called this function, + and the lines below it list the functions this one called. + This line lists: + index A unique number given to each element of the table. + Index numbers are sorted numerically. + The index number is printed next to every function name so + it is easier to look up where the function is in the table. + + % time This is the percentage of the `total' time that was spent + in this function and its children. Note that due to + different viewpoints, functions excluded by options, etc, + these numbers will NOT add up to 100%. + + self This is the total amount of time spent in this function. + + children This is the total amount of time propagated into this + function by its children. + + called This is the number of times the function was called. + If the function called itself recursively, the number + only includes non-recursive calls, and is followed by + a `+' and the number of recursive calls. + + name The name of the current function. The index number is + printed after it. If the function is a member of a + cycle, the cycle number is printed between the + function's name and the index number. + + + For the function's parents, the fields have the following meanings: + + self This is the amount of time that was propagated directly + from the function into this parent. + + children This is the amount of time that was propagated from + the function's children into this parent. + + called This is the number of times this parent called the + function `/' the total number of times the function + was called. Recursive calls to the function are not + included in the number after the `/'. + + name This is the name of the parent. The parent's index + number is printed after it. If the parent is a + member of a cycle, the cycle number is printed between + the name and the index number. + + If the parents of the function cannot be determined, the word + `' is printed in the `name' field, and all the other + fields are blank. + + For the function's children, the fields have the following meanings: + + self This is the amount of time that was propagated directly + from the child into the function. + + children This is the amount of time that was propagated from the + child's children to the function. + + called This is the number of times the function called + this child `/' the total number of times the child + was called. Recursive calls by the child are not + listed in the number after the `/'. + + name This is the name of the child. The child's index + number is printed after it. If the child is a + member of a cycle, the cycle number is printed + between the name and the index number. + + If there are any cycles (circles) in the call graph, there is an + entry for the cycle-as-a-whole. This entry shows who called the + cycle (as parents) and the members of the cycle (as children.) + The `+' recursive calls entry shows the number of function calls that + were internal to the cycle, and the calls entry for each member shows, + for that member, how many times it was called from other members of + the cycle. + +Copyright (C) 2012-2023 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. + +Index by function name + + [4] cmpInt [5] generate_random_edge_weight [1] random_connected_graph diff --git a/compose.yaml b/compose.yaml index e1245a5..5684408 100644 --- a/compose.yaml +++ b/compose.yaml @@ -14,6 +14,5 @@ services: # - NODE_ENV=development user: root command: sleep infinity - volumes: steingen-volume: diff --git a/example2.txt b/example2.txt new file mode 100644 index 0000000..054e86f --- /dev/null +++ b/example2.txt @@ -0,0 +1,512 @@ +Generated graph edges: +Edge 0 -> 1 +Edge 0 -> 2 +Edge 0 -> 6 +Edge 0 -> 8 +Edge 0 -> 9 +Edge 0 -> 10 +Edge 0 -> 13 +Edge 0 -> 14 +Edge 0 -> 15 +Edge 0 -> 22 +Edge 0 -> 23 +Edge 0 -> 24 +Edge 0 -> 25 +Edge 0 -> 26 +Edge 0 -> 27 +Edge 0 -> 28 +Edge 0 -> 29 +Edge 0 -> 30 +Edge 0 -> 31 +Edge 0 -> 32 +Edge 0 -> 35 +Edge 0 -> 38 +Edge 1 -> 3 +Edge 1 -> 7 +Edge 1 -> 8 +Edge 1 -> 10 +Edge 1 -> 11 +Edge 1 -> 12 +Edge 1 -> 13 +Edge 1 -> 14 +Edge 1 -> 15 +Edge 1 -> 17 +Edge 1 -> 18 +Edge 1 -> 19 +Edge 1 -> 20 +Edge 1 -> 21 +Edge 1 -> 22 +Edge 1 -> 24 +Edge 1 -> 25 +Edge 1 -> 27 +Edge 1 -> 28 +Edge 1 -> 29 +Edge 1 -> 30 +Edge 1 -> 31 +Edge 1 -> 32 +Edge 1 -> 33 +Edge 1 -> 35 +Edge 1 -> 36 +Edge 1 -> 37 +Edge 1 -> 39 +Edge 2 -> 3 +Edge 2 -> 4 +Edge 2 -> 7 +Edge 2 -> 8 +Edge 2 -> 9 +Edge 2 -> 12 +Edge 2 -> 13 +Edge 2 -> 14 +Edge 2 -> 15 +Edge 2 -> 16 +Edge 2 -> 17 +Edge 2 -> 18 +Edge 2 -> 19 +Edge 2 -> 20 +Edge 2 -> 21 +Edge 2 -> 22 +Edge 2 -> 24 +Edge 2 -> 27 +Edge 2 -> 29 +Edge 2 -> 30 +Edge 2 -> 31 +Edge 2 -> 33 +Edge 2 -> 34 +Edge 2 -> 36 +Edge 2 -> 38 +Edge 2 -> 39 +Edge 3 -> 4 +Edge 3 -> 6 +Edge 3 -> 7 +Edge 3 -> 9 +Edge 3 -> 10 +Edge 3 -> 12 +Edge 3 -> 13 +Edge 3 -> 14 +Edge 3 -> 15 +Edge 3 -> 16 +Edge 3 -> 17 +Edge 3 -> 18 +Edge 3 -> 19 +Edge 3 -> 21 +Edge 3 -> 22 +Edge 3 -> 23 +Edge 3 -> 24 +Edge 3 -> 26 +Edge 3 -> 27 +Edge 3 -> 28 +Edge 3 -> 31 +Edge 3 -> 32 +Edge 3 -> 33 +Edge 3 -> 34 +Edge 3 -> 35 +Edge 3 -> 38 +Edge 4 -> 5 +Edge 4 -> 6 +Edge 4 -> 7 +Edge 4 -> 8 +Edge 4 -> 9 +Edge 4 -> 11 +Edge 4 -> 12 +Edge 4 -> 13 +Edge 4 -> 14 +Edge 4 -> 15 +Edge 4 -> 17 +Edge 4 -> 19 +Edge 4 -> 20 +Edge 4 -> 21 +Edge 4 -> 22 +Edge 4 -> 23 +Edge 4 -> 25 +Edge 4 -> 27 +Edge 4 -> 28 +Edge 4 -> 29 +Edge 4 -> 30 +Edge 4 -> 31 +Edge 4 -> 32 +Edge 4 -> 33 +Edge 4 -> 35 +Edge 4 -> 38 +Edge 4 -> 39 +Edge 5 -> 8 +Edge 5 -> 9 +Edge 5 -> 10 +Edge 5 -> 11 +Edge 5 -> 12 +Edge 5 -> 16 +Edge 5 -> 17 +Edge 5 -> 18 +Edge 5 -> 22 +Edge 5 -> 24 +Edge 5 -> 25 +Edge 5 -> 26 +Edge 5 -> 28 +Edge 5 -> 34 +Edge 5 -> 36 +Edge 5 -> 37 +Edge 5 -> 38 +Edge 5 -> 39 +Edge 6 -> 7 +Edge 6 -> 9 +Edge 6 -> 10 +Edge 6 -> 11 +Edge 6 -> 12 +Edge 6 -> 13 +Edge 6 -> 14 +Edge 6 -> 15 +Edge 6 -> 17 +Edge 6 -> 18 +Edge 6 -> 20 +Edge 6 -> 22 +Edge 6 -> 23 +Edge 6 -> 26 +Edge 6 -> 27 +Edge 6 -> 28 +Edge 6 -> 29 +Edge 6 -> 30 +Edge 6 -> 33 +Edge 6 -> 36 +Edge 6 -> 37 +Edge 7 -> 8 +Edge 7 -> 9 +Edge 7 -> 12 +Edge 7 -> 14 +Edge 7 -> 15 +Edge 7 -> 17 +Edge 7 -> 18 +Edge 7 -> 19 +Edge 7 -> 20 +Edge 7 -> 23 +Edge 7 -> 24 +Edge 7 -> 26 +Edge 7 -> 27 +Edge 7 -> 32 +Edge 7 -> 33 +Edge 7 -> 34 +Edge 7 -> 35 +Edge 7 -> 37 +Edge 7 -> 38 +Edge 8 -> 10 +Edge 8 -> 12 +Edge 8 -> 13 +Edge 8 -> 14 +Edge 8 -> 15 +Edge 8 -> 17 +Edge 8 -> 18 +Edge 8 -> 19 +Edge 8 -> 20 +Edge 8 -> 21 +Edge 8 -> 23 +Edge 8 -> 25 +Edge 8 -> 27 +Edge 8 -> 30 +Edge 8 -> 31 +Edge 8 -> 35 +Edge 8 -> 37 +Edge 8 -> 38 +Edge 9 -> 10 +Edge 9 -> 11 +Edge 9 -> 13 +Edge 9 -> 14 +Edge 9 -> 15 +Edge 9 -> 16 +Edge 9 -> 17 +Edge 9 -> 19 +Edge 9 -> 20 +Edge 9 -> 21 +Edge 9 -> 24 +Edge 9 -> 25 +Edge 9 -> 26 +Edge 9 -> 27 +Edge 9 -> 29 +Edge 9 -> 31 +Edge 9 -> 33 +Edge 9 -> 34 +Edge 9 -> 37 +Edge 9 -> 39 +Edge 10 -> 11 +Edge 10 -> 12 +Edge 10 -> 15 +Edge 10 -> 16 +Edge 10 -> 17 +Edge 10 -> 18 +Edge 10 -> 19 +Edge 10 -> 20 +Edge 10 -> 21 +Edge 10 -> 22 +Edge 10 -> 24 +Edge 10 -> 25 +Edge 10 -> 28 +Edge 10 -> 29 +Edge 10 -> 32 +Edge 10 -> 33 +Edge 10 -> 34 +Edge 10 -> 35 +Edge 10 -> 38 +Edge 11 -> 12 +Edge 11 -> 13 +Edge 11 -> 15 +Edge 11 -> 16 +Edge 11 -> 20 +Edge 11 -> 21 +Edge 11 -> 22 +Edge 11 -> 24 +Edge 11 -> 25 +Edge 11 -> 27 +Edge 11 -> 28 +Edge 11 -> 30 +Edge 11 -> 31 +Edge 11 -> 32 +Edge 11 -> 35 +Edge 11 -> 36 +Edge 11 -> 38 +Edge 11 -> 39 +Edge 12 -> 13 +Edge 12 -> 14 +Edge 12 -> 15 +Edge 12 -> 16 +Edge 12 -> 18 +Edge 12 -> 19 +Edge 12 -> 20 +Edge 12 -> 21 +Edge 12 -> 24 +Edge 12 -> 25 +Edge 12 -> 29 +Edge 12 -> 31 +Edge 12 -> 32 +Edge 12 -> 33 +Edge 12 -> 34 +Edge 12 -> 35 +Edge 12 -> 36 +Edge 12 -> 37 +Edge 12 -> 38 +Edge 12 -> 39 +Edge 13 -> 14 +Edge 13 -> 15 +Edge 13 -> 16 +Edge 13 -> 17 +Edge 13 -> 18 +Edge 13 -> 21 +Edge 13 -> 22 +Edge 13 -> 24 +Edge 13 -> 27 +Edge 13 -> 31 +Edge 13 -> 32 +Edge 13 -> 34 +Edge 13 -> 35 +Edge 13 -> 38 +Edge 14 -> 15 +Edge 14 -> 16 +Edge 14 -> 17 +Edge 14 -> 19 +Edge 14 -> 21 +Edge 14 -> 22 +Edge 14 -> 23 +Edge 14 -> 24 +Edge 14 -> 25 +Edge 14 -> 30 +Edge 14 -> 31 +Edge 14 -> 32 +Edge 14 -> 33 +Edge 14 -> 34 +Edge 14 -> 35 +Edge 14 -> 37 +Edge 14 -> 39 +Edge 15 -> 16 +Edge 15 -> 17 +Edge 15 -> 19 +Edge 15 -> 21 +Edge 15 -> 23 +Edge 15 -> 24 +Edge 15 -> 25 +Edge 15 -> 27 +Edge 15 -> 28 +Edge 15 -> 29 +Edge 15 -> 30 +Edge 15 -> 36 +Edge 15 -> 37 +Edge 15 -> 38 +Edge 15 -> 39 +Edge 16 -> 17 +Edge 16 -> 18 +Edge 16 -> 19 +Edge 16 -> 20 +Edge 16 -> 22 +Edge 16 -> 23 +Edge 16 -> 24 +Edge 16 -> 27 +Edge 16 -> 28 +Edge 16 -> 29 +Edge 16 -> 31 +Edge 16 -> 32 +Edge 16 -> 33 +Edge 16 -> 35 +Edge 16 -> 38 +Edge 17 -> 18 +Edge 17 -> 19 +Edge 17 -> 21 +Edge 17 -> 23 +Edge 17 -> 25 +Edge 17 -> 27 +Edge 17 -> 28 +Edge 17 -> 29 +Edge 17 -> 31 +Edge 17 -> 32 +Edge 17 -> 33 +Edge 17 -> 36 +Edge 17 -> 37 +Edge 17 -> 38 +Edge 17 -> 39 +Edge 18 -> 19 +Edge 18 -> 20 +Edge 18 -> 21 +Edge 18 -> 22 +Edge 18 -> 23 +Edge 18 -> 25 +Edge 18 -> 26 +Edge 18 -> 27 +Edge 18 -> 28 +Edge 18 -> 29 +Edge 18 -> 33 +Edge 18 -> 35 +Edge 18 -> 36 +Edge 18 -> 37 +Edge 18 -> 38 +Edge 18 -> 39 +Edge 19 -> 20 +Edge 19 -> 21 +Edge 19 -> 22 +Edge 19 -> 23 +Edge 19 -> 26 +Edge 19 -> 27 +Edge 19 -> 29 +Edge 19 -> 32 +Edge 19 -> 34 +Edge 19 -> 35 +Edge 19 -> 36 +Edge 19 -> 37 +Edge 19 -> 38 +Edge 19 -> 39 +Edge 20 -> 21 +Edge 20 -> 23 +Edge 20 -> 24 +Edge 20 -> 25 +Edge 20 -> 26 +Edge 20 -> 28 +Edge 20 -> 29 +Edge 20 -> 31 +Edge 20 -> 32 +Edge 20 -> 37 +Edge 20 -> 39 +Edge 21 -> 22 +Edge 21 -> 23 +Edge 21 -> 25 +Edge 21 -> 27 +Edge 21 -> 29 +Edge 21 -> 31 +Edge 21 -> 32 +Edge 21 -> 33 +Edge 21 -> 35 +Edge 21 -> 36 +Edge 21 -> 38 +Edge 21 -> 39 +Edge 22 -> 23 +Edge 22 -> 24 +Edge 22 -> 26 +Edge 22 -> 28 +Edge 22 -> 29 +Edge 22 -> 34 +Edge 22 -> 37 +Edge 22 -> 38 +Edge 22 -> 39 +Edge 23 -> 26 +Edge 23 -> 27 +Edge 23 -> 30 +Edge 23 -> 32 +Edge 23 -> 33 +Edge 23 -> 34 +Edge 23 -> 37 +Edge 23 -> 38 +Edge 24 -> 28 +Edge 24 -> 31 +Edge 24 -> 33 +Edge 24 -> 36 +Edge 24 -> 37 +Edge 24 -> 38 +Edge 24 -> 39 +Edge 25 -> 26 +Edge 25 -> 27 +Edge 25 -> 30 +Edge 25 -> 33 +Edge 25 -> 34 +Edge 25 -> 36 +Edge 25 -> 37 +Edge 25 -> 38 +Edge 25 -> 39 +Edge 26 -> 27 +Edge 26 -> 28 +Edge 26 -> 29 +Edge 26 -> 30 +Edge 26 -> 32 +Edge 26 -> 34 +Edge 26 -> 35 +Edge 26 -> 36 +Edge 26 -> 37 +Edge 26 -> 38 +Edge 27 -> 29 +Edge 27 -> 30 +Edge 27 -> 31 +Edge 27 -> 35 +Edge 27 -> 36 +Edge 27 -> 37 +Edge 27 -> 39 +Edge 28 -> 29 +Edge 28 -> 31 +Edge 28 -> 33 +Edge 28 -> 35 +Edge 28 -> 38 +Edge 29 -> 30 +Edge 29 -> 34 +Edge 29 -> 35 +Edge 29 -> 37 +Edge 29 -> 39 +Edge 30 -> 31 +Edge 30 -> 32 +Edge 30 -> 34 +Edge 30 -> 36 +Edge 30 -> 37 +Edge 30 -> 38 +Edge 31 -> 32 +Edge 31 -> 33 +Edge 31 -> 34 +Edge 31 -> 35 +Edge 31 -> 39 +Edge 32 -> 33 +Edge 32 -> 35 +Edge 32 -> 36 +Edge 32 -> 37 +Edge 32 -> 38 +Edge 32 -> 39 +Edge 33 -> 34 +Edge 33 -> 35 +Edge 34 -> 36 +Edge 34 -> 37 +Edge 34 -> 38 +Edge 34 -> 39 +Edge 35 -> 36 +Edge 35 -> 37 +Edge 35 -> 38 +Edge 36 -> 38 +Edge 37 -> 38 +Edge 37 -> 39 +Random groups: +Group 0: 0 23 +Group 1: 10 29 +Group 2: 16 25 +Group 3: 30 31 +Group 4: 5 18 +Group 5: 20 27 +Group 6: 1 15 +Group 7: 2 22 +Group 8: 11 16 +Group 9: 0 8 diff --git a/include/rand_large.h b/include/rand_large.h new file mode 100644 index 0000000..0f84356 --- /dev/null +++ b/include/rand_large.h @@ -0,0 +1,17 @@ +#ifndef RAND_R_LARGE_H +#define RAND_R_LARGE_H + +#include + + +/** + * Generates a large random number by combining two `rand_r` calls. + * + * @param seed A pointer to an unsigned 16-bit seed used for the random number generator. + * The seed is updated after each call to maintain the sequence. + * + * @return A 64-bit unsigned random number. + */ +uint64_t rand_r_large(uint16_t* seed); + +#endif // RAND_R_LARGE_H diff --git a/include/random_edge_weight.h b/include/random_edge_weight.h new file mode 100644 index 0000000..668232b --- /dev/null +++ b/include/random_edge_weight.h @@ -0,0 +1,14 @@ +#ifndef GEOMETRY_WEIGHTS_H +#define GEOMETRY_WEIGHTS_H + +#include +#include + +// Function to embed vertices into 2D space +void embed_vertices(int N, float B, float *x, float *y, uint16_t* seed); + +// Function to generate random edge weight +float generate_random_edge_weight(float *x, float *y, unsigned int N, unsigned int s, unsigned int t, + float a, float b, const char *family, const char *type, uint16_t* seed); + +#endif // GEOMETRY_WEIGHTS_H diff --git a/include/random_graph.h b/include/random_graph.h index 6d1abe8..94104db 100644 --- a/include/random_graph.h +++ b/include/random_graph.h @@ -4,20 +4,22 @@ #include #include #include +#include +#include "rand_large.h" // Edge structure typedef struct Edge { - int src; - int dest; + uint32_t src; + uint32_t dest; } Edge; // Function prototypes int cmpInt(const void *a, const void *b); -unsigned int uv2index(unsigned int u, unsigned int v, unsigned int n); -unsigned int min(unsigned int u, unsigned int v); -unsigned int max(unsigned int u, unsigned int v); -int index2uv(unsigned int index, unsigned int n, int *u, int *v); -void random_spanning_tree( - unsigned int n, unsigned int m, unsigned int seed, Edge *edges); +uint64_t uv2index(uint32_t u, uint32_t v, uint32_t n); +uint32_t min(uint32_t u, uint32_t v); +uint32_t max(uint32_t u, uint32_t v); +int8_t index2uv(uint64_t index, uint32_t n, uint32_t *u, uint32_t *v); +void random_connected_graph( + uint32_t n, uint64_t m, Edge *edges, uint16_t* seed); #endif // RANDOM_GRAPH_H diff --git a/include/random_group_steiner.h b/include/random_group_steiner.h new file mode 100644 index 0000000..372631d --- /dev/null +++ b/include/random_group_steiner.h @@ -0,0 +1,13 @@ +#ifndef RANDOM_GROUP_STEINER_H +#define RANDOM_GROUP_STEINER_H + +#include "random_groups.h" +#include "random_graph.h" + +// Function to generate a random Group Steiner instance +void generate_random_group_steiner_instance( + uint32_t n, uint32_t m, uint16_t k, const char *filename, + float vertex_a, float vertex_b, const char *vertex_weight_type, + float edge_a, float edge_b, const char *edge_weight_family, const char *edge_weight_type, const char *instance_type, uint16_t* seed); + +#endif // RANDOM_GROUP_STEINER_H diff --git a/include/random_groups.h b/include/random_groups.h index 8c291f9..cf1fb10 100644 --- a/include/random_groups.h +++ b/include/random_groups.h @@ -3,14 +3,16 @@ #include #include +#include // Struct for representing groups typedef struct { - unsigned int *group; // Pointer to an array of group members - unsigned int size; // Number of members in the group + uint32_t *group; // Pointer to an array of group members + uint32_t size; // Number of members in the group } Group; // Function to generate random groups -void generate_random_groups(unsigned int n, unsigned int k, Group **groups); +void shuffle(uint32_t *array, uint32_t size, uint16_t* seed); +void generate_random_groups(uint32_t n, uint16_t k, Group *groups, uint16_t* seed); #endif // RANDOM_GROUPS_H diff --git a/include/random_vertex_weight.h b/include/random_vertex_weight.h new file mode 100644 index 0000000..8a27629 --- /dev/null +++ b/include/random_vertex_weight.h @@ -0,0 +1,12 @@ +#ifndef RANDOM_VERTEX_WEIGHT_H +#define RANDOM_VERTEX_WEIGHT_H + +#include +#include +#include +#include + +// Function to generate a random vertex weight +float generate_random_vertex_weight(const char *weight_type, float a, float b, uint16_t* seed); + +#endif // RANDOM_VERTEX_WEIGHT_H diff --git a/random_instance.stp b/random_instance.stp new file mode 100644 index 0000000..e69de29 diff --git a/src/main.c b/src/main.c index ec43c65..64a7584 100644 --- a/src/main.c +++ b/src/main.c @@ -1,38 +1,27 @@ #include -#include -#include "random_graph.h" -#include "random_groups.h" +#include "random_group_steiner.h" int main() { - unsigned int n = 20, m = 80, k = 4, seed = 5; - Edge *edges = malloc(m * sizeof(Edge)); - if (!edges) { - fprintf(stderr, "Error: Memory allocation of EDGE array: edges FAILED.\n"); - exit(EXIT_FAILURE); - } - - random_spanning_tree(n, m, seed, edges); - - printf("Generated graph edges:\n"); - for (unsigned int i = 0; i < m; i++) { - printf("Edge %d -> %d\n", edges[i].src, edges[i].dest); - } + uint32_t n = 90000; // Number of vertices + uint64_t m = 1000000; // Number of edges + uint16_t k = 2000; // Number of groups + uint16_t seed = 12345; - Group *groups; - generate_random_groups(n, k, &groups); - // Print groups - printf("Random groups:\n"); - for (unsigned int i = 0; i < k; i++) { - printf("Group %u: ", i); - for (unsigned int j = 0; j < groups[i].size; j++) { - printf("%u ", groups[i].group[j]); - } - printf("\n"); - free(groups[i].group); // Free each group's array - } - free(groups); // Free the groups array - free(edges); + const char *filename = "random_instance.stp"; + float vertex_a = 1.0, vertex_b = 10.0; + const char *vertex_weight_type = "float"; + float edge_a = 1.0, edge_b = 10.0; + const char *edge_weight_family = "random"; + const char *edge_weight_type = "float"; + const char *instance_type = "Node Weighted Group Steiner Tree Instance"; + + generate_random_group_steiner_instance( + n, m, k, filename, + vertex_a, vertex_b, vertex_weight_type, + edge_a, edge_b, edge_weight_family, edge_weight_type, instance_type, &seed); + + printf("Random Group Steiner instance written to %s\n", filename); return 0; } diff --git a/src/rand_large.c b/src/rand_large.c new file mode 100644 index 0000000..bd81ee5 --- /dev/null +++ b/src/rand_large.c @@ -0,0 +1,12 @@ +#include +#include +#include "rand_large.h" + +/** + * Generates a large random number by combining two `rand_r` calls. + */ +uint64_t rand_r_large(uint16_t* seed) { + // Combine two `rand_r` calls for a larger range + uint64_t large_random = ((uint64_t)rand_r((unsigned int* )seed) << 31) | rand_r((unsigned int* )seed); + return large_random; +} diff --git a/src/random_edge_weight.c b/src/random_edge_weight.c new file mode 100644 index 0000000..3f9ae89 --- /dev/null +++ b/src/random_edge_weight.c @@ -0,0 +1,49 @@ +#include "random_edge_weight.h" +#include +#include +#include + +// Embed vertices into 2D space with random coordinates between 0 and B +void embed_vertices(int N, float B, float *x, float *y, uint16_t* seed) { + for (int i = 0; i < N; i++) { + x[i] = ((float)rand_r((unsigned int* )seed) / RAND_MAX) * B; + y[i] = ((float)rand_r((unsigned int* )seed) / RAND_MAX) * B; + } +} + +// Generate random edge weight based on the given weight type +float generate_random_edge_weight(float *x, float *y, unsigned int N, unsigned int s, unsigned int t, + float a, float b, const char *family, const char *type, uint16_t* seed) { + if (s >= N || t >= N) { + fprintf(stderr, "Error: Vertex indices s (%u) or t (%u) exceed the number of vertices (%d).\n", s, t, N); + exit(EXIT_FAILURE); + } + + float weight = 1.0; + + if (strcmp(family, "euclid") == 0) { + // Euclidean distance + float dx = x[s] - x[t]; + float dy = y[s] - y[t]; + weight += sqrt(dx * dx + dy * dy); + } else if (strcmp(family, "grid") == 0) { + // Manhattan distance + weight += fabs(x[s] - x[t]) + fabs(y[s] - y[t]); + } else if (strcmp(family, "random") == 0) { + // Uniform random weight + weight += a + ((float)rand_r((unsigned int* )seed) / RAND_MAX) * (b - a); + } else { + fprintf(stderr, "Error: Invalid weight type '%s'. Use 'euclid', 'grid', or 'random'.\n", family); + exit(EXIT_FAILURE); + } + + // Cast to integer if the type is "int" + if (strcmp(type, "int") == 0) { + weight = (float)((int)weight); + } else if (strcmp(type, "float") != 0) { + fprintf(stderr, "Error: Invalid type '%s'. Use 'int' or 'float'.\n", type); + exit(EXIT_FAILURE); + } + + return weight; +} diff --git a/src/random_graph.c b/src/random_graph.c index 0b11093..0c97da5 100644 --- a/src/random_graph.c +++ b/src/random_graph.c @@ -1,50 +1,60 @@ #include "random_graph.h" + int cmpInt(const void *a, const void *b) { - return (*(unsigned int *)a - *(unsigned int *)b); + int64_t int_a = *(int64_t *)a; + int64_t int_b = *(int64_t *)b; + + // Return the difference (int_a - int_b) + return (int) ((int_a > int_b) - (int_a < int_b)); // Returns -1, 0, or 1 } -inline unsigned int min(unsigned int u, unsigned int v){ +inline uint32_t min(uint32_t u, uint32_t v){ return u < v ? u : v; } -inline unsigned int max(unsigned int u, unsigned int v){ +inline uint32_t max(uint32_t u, uint32_t v){ return u < v ? v : u; } -unsigned int uv2index(unsigned int u, unsigned int v, unsigned int n) { +uint64_t uv2index(uint32_t u, uint32_t v, uint32_t n) { if (u < n && v < n && u < v) { - unsigned int index = (u * (2*n - u - 1) / 2) + (v - u - 1); - if (index < (n * (n - 1)) / 2) { - return index; + uint64_t uu = (uint64_t)(u); + uint64_t vv = (uint64_t)(v); + uint64_t nn = (uint64_t)(n); + uint64_t mmax = (nn * (nn - 1)) / 2; + uint64_t index = (uu * (2*nn - uu - 1))/2 + (vv - uu - 1); + if (index < mmax) { + return (uint64_t)index; } else { fprintf(stderr, "Error: Formula should be checked for index calculation.\n"); - return (unsigned int)-1; + return (uint64_t)(-1); } } fprintf(stderr, "Error: Invalid u or v values.\n"); - return (unsigned int)(-1); + return (uint64_t)(-1); } -int index2uv(unsigned int index, unsigned int n, int *u, int *v) { +int8_t index2uv(uint64_t index, uint32_t n, uint32_t *u, uint32_t *v) { if (index < (n * (n - 1)) / 2) { - long long nn = (long long)n; - long long indexx = (long long)index; - long long dd = (2 * nn - 1) * (2 * nn - 1) - 8 * indexx; - double uur = ((double)(2 * n - 1) - sqrt(dd)) / 2; - long long uu = ((double)(2 * n - 1) - sqrt(dd)) / 2; - long long vv = uu + index + 1 - uu * (2*n - uu - 1) / 2; + int64_t nn = (int64_t)n; + int64_t indexx = (int64_t)index; + int64_t dd = (2 * nn - 1) * (2 * nn - 1) - 8 * indexx; + // double uur = ((double)(2 * n - 1) - sqrt(dd)) / 2; + int64_t uu = ((double)(2 * n - 1) - sqrt(dd)) / 2; + int64_t vv = uu + index + 1 - uu * (2*n - uu - 1) / 2; if (uu >= 0 && uu < n && vv >= uu + 1 && vv < n) { - *u = (unsigned int)uu; - *v = (unsigned int)vv; + *u = (uint32_t)uu; + *v = (uint32_t)vv; return 0; + } else { - printf("n: %lld\n", nn); - printf("index: %lld\n", indexx); - printf("D: %lld\n", dd); - printf("u: %.10f\n", uur); - fprintf(stderr, "Error: Invalid calculated u or v values. Index: %d, u = %lld, v=%lld\n", index, uu, vv); + // printf("n: %lu\n", nn); + // printf("index: %lu\n", indexx); + // printf("D: %d\n", dd); + // printf("u: %.10f\n", uur); + // fprintf(stderr, "Error: Invalid calculated u or v values. Index: %d, u = %d, v=%d\n", index, uu, vv); return -1; } } @@ -52,83 +62,96 @@ int index2uv(unsigned int index, unsigned int n, int *u, int *v) { return -1; } -void random_spanning_tree( - unsigned int n, unsigned int m, unsigned int seed, Edge *edges) { +void random_connected_graph( + uint32_t n, uint64_t m, Edge *edges, uint16_t* seed) { if (m > n * (n - 1) / 2) { fprintf(stderr, "Error: Number of edges exceeds the maximum possible for %u vertices.\n", n); exit(EXIT_FAILURE); } - unsigned int mmax = n * (n - 1) / 2; // Maximum possible number of edges - unsigned int *N = malloc(n * sizeof(unsigned int)); // Vertices array - unsigned int *M = malloc(mmax * sizeof(unsigned int)); // All edge indices - unsigned int *T = malloc(m * sizeof(unsigned int)); // Selected edges for the graph + uint64_t mmax = (uint64_t)n * ((uint64_t)n - 1) / 2; // Maximum possible number of edges + uint32_t *N = malloc(n * sizeof(uint32_t)); // Vertices array + uint64_t *M = malloc(mmax * sizeof(uint64_t)); // All edge indices + uint64_t *T = malloc(m * sizeof(uint64_t)); // Selected edges for the graph if (!N || !M || !T) { - fprintf(stderr, "Error: Memory allocation failed.\n"); - free(N); free(M); free(T); - exit(EXIT_FAILURE); + fprintf(stderr, "Error: Memory allocation of arrays N, M or T failed.\n"); + free(T); + free(M); + free(N); + exit(EXIT_FAILURE); } // Initialize vertex and edge index arrays - for (unsigned int i = 0; i < n; i++) N[i] = i; - for (unsigned int i = 0; i < mmax; i++) M[i] = i; + for (uint32_t i = 0; i < n; i++) N[i] = i; + for (uint64_t i = 0; i < mmax; i++) M[i] = i; // Seed random number generator and shuffle vertices - srand(seed); - for (unsigned int i = n - 1; i > 0; i--) { - unsigned int j = rand() % (i + 1); - unsigned int temp = N[i]; + for (uint32_t i = n - 1; i > 0; i--) { + uint32_t j = rand_r_large(seed) % (i + 1); + uint32_t temp = N[i]; N[i] = N[j]; N[j] = temp; } // Build spanning tree by randomly selecting edges - for (unsigned int v = 1; v < n; v++) { - unsigned int u = rand() % v; - unsigned int index = uv2index(min(N[u],N[v]), max(N[u],N[v]), n); - if (index == (unsigned int)-1) { - free(N); free(M); free(T); + for (uint32_t v = 1; v < n; v++) { + uint32_t u = rand_r_large(seed) % v; + uint64_t index = uv2index(min(N[u],N[v]), max(N[u],N[v]), n); + if (index == (uint64_t)(-1)) { + free(T); + free(M); + free(N); exit(EXIT_FAILURE); } + if (index >= mmax){ + fprintf(stderr, "u = %u; v = %u", u, v); + fprintf(stderr, "index = %lu; mmax = %lu", index, mmax); + } T[v - 1] = index; // Add edge index to T } // Sort the initial edges of the spanning tree - qsort(T, n - 1, sizeof(unsigned int), cmpInt); + qsort(T, n - 1, sizeof(uint64_t), cmpInt); // put all selected edges back to the array (last n-1 elements of M) - for (int i = n-2; i >= 0; i--) { - unsigned int temp = M[mmax - 1 - n + 2 + i]; + for (int64_t i = n-2; i >= 0; i--) { + if (T[i] > mmax){ + fprintf(stderr, "T[i] = %lu; mmax = %lu", T[i], mmax); + + } + uint32_t temp = M[mmax - 1 - n + 2 + i]; M[mmax - 1 - n + 2 + i] = M[T[i]]; M[T[i]] = temp; } // Randomly shuffle remaining edges in M[0,...,mmax - n] - for (unsigned int i = mmax - n; i > 0; i--) { - unsigned int j = rand() % (i + 1); - unsigned int temp = M[i]; + for (int64_t i = mmax - n; i > 0; i--) { + uint32_t j = rand_r_large(seed) % (i + 1); + uint32_t temp = M[i]; M[i] = M[j]; M[j] = temp; } // Select the first m - n + 1 additional edges - for (unsigned int i = 0; i < m - n + 1; i++) { + for (uint64_t i = 0; i < m - n + 1; i++) { T[n - 1 + i] = M[i]; } // Sort the entire T array - qsort(T, m, sizeof(unsigned int), cmpInt); + qsort(T, m, sizeof(uint64_t), cmpInt); // Convert indices to edges and create the edge array - unsigned int check = m; - for (unsigned int i = 0; i < m; i++) { - int u, v; + uint64_t check = m; + for (uint64_t i = 0; i < m; i++) { + uint32_t u, v; if (index2uv(T[i], n, &u, &v) == -1) { - free(N); free(M); free(T); free(edges); + free(T); + free(M); + free(N); exit(EXIT_FAILURE); } if (T[i] == check){ @@ -144,7 +167,7 @@ void random_spanning_tree( // Output edges // Cleanup - free(N); - free(M); free(T); + free(M); + free(N); } diff --git a/src/random_group_steiner.c b/src/random_group_steiner.c new file mode 100644 index 0000000..23853c4 --- /dev/null +++ b/src/random_group_steiner.c @@ -0,0 +1,131 @@ +#include +#include +#include +#include +#include "random_graph.h" +#include "random_groups.h" +#include "random_edge_weight.h" +#include "random_vertex_weight.h" + +void generate_random_group_steiner_instance( + uint32_t n, uint32_t m, uint16_t k, const char *filename, + float vertex_a, float vertex_b, const char *vertex_weight_type, + float edge_a, float edge_b, const char *edge_weight_family, const char *edge_weight_type, const char *instance_type, uint16_t* seed) { + + // Open file for writing + FILE *file = fopen(filename, "w"); + if (!file) { + fprintf(stderr, "Error: Could not open file %s for writing.\n", filename); + exit(EXIT_FAILURE); + } + + // Generate a random connected graph + Edge *edges = (Edge *)malloc(m * sizeof(Edge)); + if (!edges) { + fprintf(stderr, "Error: Memory allocation failed for edges.\n"); + fclose(file); + exit(EXIT_FAILURE); + } + // uint64_t mmax = (uint64_t)(n * (n - 1) / 2); + random_connected_graph(n, m, edges, seed); + + // Embed vertices into 2D space for geometry-based edge weights + float *x = (float *)malloc(n * sizeof(float)); + if (!x) { + fprintf(stderr, "Error: Memory allocation failed for array x.\n"); + free(edges); + fclose(file); + exit(EXIT_FAILURE); + } + + float *y = (float *)malloc(n * sizeof(float)); + if (!y) { + fprintf(stderr, "Error: Memory allocation failed for array y.\n"); + free(x); + free(edges); + fclose(file); + exit(EXIT_FAILURE); + } + + embed_vertices(n, 100.0, x, y, seed); // Embedding vertices into [0, 100] space + + + // Allocate memory for groups + Group *groups = (Group *)malloc(k * sizeof(Group)); + if (!groups) { + fprintf(stderr, "Error: Memory allocation failed for groups.\n"); + free(y); + free(x); + free(edges); + exit(EXIT_FAILURE); + } + for (unsigned int i = 0; i < k; i++) { + groups[i].group = (uint32_t *)malloc(n * sizeof(uint32_t)); + groups[i].size = 0; + if (!groups[i].group) { + fprintf(stderr, "Error: Memory allocation failed for group %u.\n", i); + for (unsigned int j = 0; j < i; j++) { + free(groups[j].group); + } + free(groups); + free(y); + free(x); + free(edges); + exit(EXIT_FAILURE); + } + } + // Generate random groups + generate_random_groups(n, k, groups, seed); + + // Write the .stp file header + fprintf(file, "0 string 33D32945 STP Steiner Tree Problem File\n"); + fprintf(file, "SECTION Comment\n"); + fprintf(file, "Name DWW_NWGST_%s_N=%u_M=%u_k=%u\n",edge_weight_family,n,m,k); + fprintf(file, "Remark '%s'\n",instance_type); + fprintf(file, "END\n\n"); + + // Write the graph section + fprintf(file, "SECTION Graph\n"); + fprintf(file, "Nodes %u\n", n); + fprintf(file, "Edges %u\n", m); + + // Write vertex weights + for (unsigned int i = 0; i < n; i++) { + float vertex_weight = generate_random_vertex_weight(vertex_weight_type, vertex_a, vertex_b, seed); + fprintf(file, "N %.1f\n", vertex_weight); + } + + // Write edges + for (unsigned int i = 0; i < m; i++) { + float edge_weight = generate_random_edge_weight( + x, y, n, edges[i].src, edges[i].dest, edge_a, edge_b, edge_weight_family, edge_weight_type, seed); + fprintf(file, "E %d %d %.2f\n", edges[i].src, edges[i].dest, edge_weight); + } + fprintf(file, "END\n\n"); + + // Write the terminals section + fprintf(file, "SECTION Terminals\n"); + fprintf(file, "Terminals %u\n", k); + + for (unsigned int i = 0; i < k; i++) { + fprintf(file, "T"); + for (unsigned int j = 0; j < groups[i].size; j++) { + fprintf(file, " %u", groups[i].group[j]); + } + fprintf(file, "\n"); + } + fprintf(file, "END\n\n"); + + // Write EOF + fprintf(file, "EOF\n"); + + // Clean up + for (unsigned int i = 0; i < k; i++) { + free(groups[i].group); + } + free(groups); + free(y); + free(x); + free(edges); + fclose(file); +} diff --git a/src/random_groups.c b/src/random_groups.c index 53c0af3..4f25a30 100644 --- a/src/random_groups.c +++ b/src/random_groups.c @@ -2,86 +2,80 @@ #include "random_graph.h" // Helper function to shuffle an array -void shuffle(unsigned int *array, unsigned int size) { - for (unsigned int i = size - 1; i > 0; i--) { - unsigned int j = rand() % (i + 1); - unsigned int temp = array[i]; +void shuffle(uint32_t *array, uint32_t size, uint16_t* seed) { + for (uint32_t i = size - 1; i > 0; i--) { + uint32_t j = rand_r((unsigned int* )seed) % (i + 1); + uint32_t temp = array[i]; array[i] = array[j]; array[j] = temp; } } -void generate_random_groups(unsigned int n, unsigned int k, Group **groups_out) { +void generate_random_groups(uint32_t n, uint16_t k, Group *groups, uint16_t* seed) { if (k > n) { fprintf(stderr, "Error: Number of groups (k) cannot exceed the number of vertices (n).\n"); exit(EXIT_FAILURE); } // Allocate memory for array N (vertices) and initialize - unsigned int *N = (unsigned int *)malloc(n * sizeof(unsigned int)); + uint32_t *N = (uint32_t *)malloc(n * sizeof(uint32_t)); if (!N) { fprintf(stderr, "Error: Memory allocation failed for array N.\n"); exit(EXIT_FAILURE); } - for (unsigned int i = 0; i < n; i++) { + for (uint32_t i = 0; i < n; i++) { N[i] = i; } - - // Allocate memory for groups - Group *groups = (Group *)malloc(k * sizeof(Group)); - if (!groups) { - fprintf(stderr, "Error: Memory allocation failed for groups.\n"); - free(N); - exit(EXIT_FAILURE); - } - for (unsigned int i = 0; i < k; i++) { - groups[i].group = (unsigned int *)malloc(n * sizeof(unsigned int)); - groups[i].size = 0; - if (!groups[i].group) { - fprintf(stderr, "Error: Memory allocation failed for group %u.\n", i); - for (unsigned int j = 0; j < i; j++) { - free(groups[j].group); - } - free(groups); - free(N); - exit(EXIT_FAILURE); - } - } + // Generate a random float f in the range (0, 0.5) float f; - do { - f = (float)rand() / RAND_MAX; - } while (f <= 0.0 || f >= 0.5); + f = (float) ( rand_r((unsigned int* )seed) / 2.0 ) / RAND_MAX; - unsigned int offset = (unsigned int)(f * n); + + uint32_t offset = (uint32_t)(f * n); // Shuffle the array N - shuffle(N, n); + shuffle(N, n, seed); + if (offset + k > n) { + fprintf(stderr, "Error: Number of Steiner vertices (%d) plus k (%d) is greather than n (%d). \n", offset, k, n); + free(N); + exit(EXIT_FAILURE); + } + + + uint32_t npool = n - offset - k; + uint32_t *I = (uint32_t *)malloc( npool* sizeof(uint32_t)); + if (!I) { + fprintf(stderr, "Error: Memory allocation failed for array I.\n"); + free(N); + exit(EXIT_FAILURE); + } + for (uint32_t i = 0; i < npool; i++) { + I[i] = i; + } // Distribute elements to the first part of each group - for (unsigned int i = 0; i < k; i++) { + for (uint32_t i = 0; i < k; i++) { groups[i].group[groups[i].size++] = N[offset + i]; } - // Distribute remaining elements to groups - for (unsigned int i = 0; i < k; i++) { - unsigned int start = offset + k; - unsigned int end = offset + k + (n - offset) / k - 1; - shuffle(N + start, end - start + 1); - - for (unsigned int j = start; j <= end; j++) { - groups[i].group[groups[i].size++] = N[j]; + uint32_t total = (n - offset) / k - 1; + for (uint32_t i = 0; i < k; i++) { + + shuffle(I,npool,seed); + for (uint32_t j = 0; j < total; j++) { + groups[i].group[groups[i].size++] = N[offset + k + I[j]]; } } // Sort each group - for (unsigned int i = 0; i < k; i++) { - qsort(groups[i].group, groups[i].size, sizeof(unsigned int), cmpInt); + for (uint32_t i = 0; i < k; i++) { + qsort(groups[i].group, groups[i].size, sizeof(uint32_t), cmpInt); } // Clean up + free(I); free(N); - *groups_out = groups; } diff --git a/src/random_vertex_weight.c b/src/random_vertex_weight.c new file mode 100644 index 0000000..b1ca6ba --- /dev/null +++ b/src/random_vertex_weight.c @@ -0,0 +1,20 @@ +#include "random_vertex_weight.h" +#include + +float generate_random_vertex_weight(const char *weight_type, float a, float b, uint16_t* seed) { + if (a > b) { + fprintf(stderr, "Error: Lower bound 'a' cannot be greater than upper bound 'b'.\n"); + exit(EXIT_FAILURE); + } + float random_value = 1 + a + ((float)rand_r((unsigned int* )seed) / RAND_MAX) * (b - a); + + // Check the weight type and cast appropriately + if (strcmp(weight_type, "integer") == 0) { + return (float)((int)random_value); + } else if (strcmp(weight_type, "float") == 0) { + return random_value; + } else { + fprintf(stderr, "Error: Invalid weight type '%s'. Use 'integer' or 'float'.\n", weight_type); + exit(EXIT_FAILURE); + } +}