STEINGEN/src/random_groups.c

144 lines
4.1 KiB
C

#include "random_groups.h"
#include "random_graph.h"
#include <string.h>
int cmpGroups(const void *a, const void *b) {
uint32_t int_a = *(uint32_t *)a;
uint32_t int_b = *(uint32_t *)b;
// Return the difference (int_a - int_b)
return (int) ((int_a > int_b) - (int_a < int_b)); // Returns -1, 0, or 1
}
// Helper function to shuffle an array
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(uint32_t n, uint16_t k, Group *groups, uint32_t* group_size, const char* group_size_mode, char* group_mode, 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
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 (uint32_t i = 0; i < n; i++) {
N[i] = i;
}
// Generate a random float f in the range (0, 0.5)
float f;
f = (float) ( rand_r((unsigned int* )seed) / 2.0 ) / RAND_MAX;
uint32_t offset = (uint32_t)(f * n);
// Shuffle the array 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 (uint32_t i = 0; i < k; i++) {
groups[i].group[groups[i].size++] = N[offset + i];
}
uint32_t total;
if(strcmp(group_size_mode, "auto") == 0){
total = (n - offset) / k - 1;
*group_size = total + 1;
}else if (strcmp(group_size_mode, "manual") == 0){
if (*group_size > n - offset - k ) {
fprintf(stderr, "Warning: Group size is shrinked to %d.\n", n - offset - k);
*group_size = n - offset - k;
}
total = *group_size - 1;
if(strcmp(group_mode, "disjoint") == 0){
if ( *group_size > (n - offset) / k - 1){
snprintf(group_mode, 256, "overlap");
fprintf(stderr, "Warning: Groups cannot be disjoint, because group size is too large: %d. It has to be at most %d. Switched to overlapping instance.\n", *group_size, (n - offset) / k - 1);
}
}
}else{
fprintf(stderr, "Error: Group size mode %s is not supported.\n", group_size_mode);
free(I);
free(N);
exit(EXIT_FAILURE);
}
if (strcmp(group_mode, "overlap") == 0){
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]];
}
}
}
else if (strcmp(group_mode, "disjoint") == 0){
// shuffle(I,npool,seed);
for (uint32_t i = 0; i < k; i++) {
for (uint32_t j = 0; j < total; j++) {
groups[i].group[groups[i].size++] = N[offset + k + i*total + I[j]];
}
}
}
else{
fprintf(stderr, "Error: Parameter 'group_mode' can be either 'overlap' or 'disjoint', but %s provided.\n", group_mode);
free(I);
free(N);
exit(EXIT_FAILURE);
}
//Sort each group
for (uint32_t i = 0; i < k; i++) {
qsort(groups[i].group, groups[i].size, sizeof(uint32_t), cmpGroups);
}
// Clean up
free(I);
free(N);
}