second working, with arg parser, optimized, group creation is unoptimized

This commit is contained in:
Слободан Јелић 2025-01-04 06:10:19 +01:00
parent c7fd378336
commit fe6463fd00
13 changed files with 465 additions and 157 deletions

View File

@ -6,6 +6,9 @@
"rand_large.h": "c",
"stdint.h": "c",
"random_group_steiner.h": "c",
"random_vertex_weight.h": "c"
"random_vertex_weight.h": "c",
"getopt.h": "c",
"string.h": "c",
"stdlib.h": "c"
}
}

View File

@ -1,7 +1,7 @@
# Compiler and Flags
CC = gcc
CFLAGS = -Wall -Wextra -Iinclude -g -pg -O0
# CFLAGS = -O3 -march=native -DNDEBUG -Wall -Wextra -Werror -Iinclude -s -flto -fno-math-errno
# 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

View File

@ -7,6 +7,9 @@
#include <stdint.h>
#include "rand_large.h"
// Edge structure
typedef struct Edge {
uint32_t src;
@ -15,9 +18,11 @@ typedef struct Edge {
// Function prototypes
int cmpInt(const void *a, const void *b);
uint64_t permuted(uint64_t pos, uint64_t a, uint64_t c, uint64_t n);
int8_t binarySearch(uint64_t *arr, uint64_t size, uint64_t key);
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);
uint64_t min(uint64_t u, uint64_t v);
uint64_t max(uint64_t u, uint64_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);

View File

@ -6,8 +6,8 @@
// 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,
uint32_t n, uint64_t m, uint16_t k, const char* e, const char* v, const char* p, 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);
float edge_a, float edge_b, const char *edge_weight_family, const char *edge_weight_type, float group_penalty_a, float group_penalty_b, const char* group_penalty_type, uint32_t* group_size, const char* group_size_mode, char* group_mode, const char *instance_type, const char* instance_type_code, uint16_t* seed);
#endif // RANDOM_GROUP_STEINER_H

View File

@ -13,6 +13,6 @@ typedef struct {
// Function to generate random 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);
void generate_random_groups(uint32_t n, uint16_t k, Group *groups, uint32_t* group_size, const char* group_size_mode, char* groups_disjoint, uint16_t* seed);
#endif // RANDOM_GROUPS_H

View File

1
requirements.txt Normal file
View File

@ -0,0 +1 @@
pandas

View File

@ -1,27 +1,186 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <getopt.h>
#include "random_group_steiner.h"
void print_usage(const char *prog_name) {
printf("Usage: %s [OPTIONS]\n", prog_name);
printf("\nOptions:\n");
printf(" -n <vertices> Number of vertices (default: 10)\n");
printf(" -m <edges> Number of edges (default: 30)\n");
printf(" -k <groups> Number of groups (default: 4)\n");
printf(" -s <seed> Random seed (default: 12345)\n");
printf(" -e <edgeweighted> If 'yes', non-zero edge weights are generated, else if 'no', no weights provided (default: yes)\n");
printf(" -v <nodeweighted> If 'yes', non-zero node weights are generated, else if 'no', no weights provided (default: yes)\n");
printf(" -p <grouppenalties> If 'yes', group penalites are generated, else if 'no', penalites are not generated (default: no)\n");
printf(" -f <filename> Output filename (default: auto-generated)\n");
printf(" --vertex-a <float> Lower bound for vertex weights (default: 1.0)\n");
printf(" --vertex-b <float> Upper bound for vertex weights (default: 10.0)\n");
printf(" --vertex-type <type> Vertex weight type (default: int)\n");
printf(" --edge-a <float> Lower bound for edge weights (default: 1.0)\n");
printf(" --edge-b <float> Upper bound for edge weights (default: 10.0)\n");
printf(" --edge-family <family> Edge weight family (default: RANDOM)\n");
printf(" --edge-type <type> Edge weight type (default: int)\n");
printf(" --group-penalty-a <float> Lower bound for group penalties (default: 1.0)\n");
printf(" --group-penalty-b <float> Upper bound for group penalties (default: 10.0)\n");
printf(" --group-penalty-type <type> Group penalty type (default: int)\n");
printf(" --group-size <int> Group size (default: 10.0)\n");
printf(" --group-size-mode <mode> Group size mode (default: auto)\n");
printf(" --group-mode <mode> If 'disjoint' groups tend to be disjoint, if 'overlap', groups may overlap (default: overlap)\n");
printf(" --instance-type <type> Instance type description (default: Node Weighted Group Steiner Tree Instance)\n");
}
int main() {
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;
int main(int argc, char *argv[]) {
uint32_t n = 10; // Number of vertices
uint64_t m = 30; // Number of edges
uint16_t k = 4; // Number of groups
uint16_t seed = 12345; // Random seed
const char *e = "yes";
const char *v = "yes";
const char *p = "no";
uint32_t group_size = n;
const char *filename = "random_instance.stp";
char filename[256] = "";
float vertex_a = 1.0, vertex_b = 10.0;
const char *vertex_weight_type = "float";
const char *vertex_weight_type = "int";
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";
const char *edge_weight_family = "RANDOM";
const char *edge_weight_type = "int";
float group_penalty_a = 1.0, group_penalty_b = 10.0;
const char *group_penalty_type = "int";
char instance_type[256];
char instance_type_code[256];
const char *instance_type_per_size = "Group ";
const char *instance_type_code_per_size = "G";
const char *group_size_mode = "auto";
char group_mode[256] = "overlap";
struct option long_options[] = {
{"vertex-a", required_argument, 0, 0},
{"vertex-b", required_argument, 0, 0},
{"vertex-type", required_argument, 0, 0},
{"edge-a", required_argument, 0, 0},
{"edge-b", required_argument, 0, 0},
{"edge-family", required_argument, 0, 0},
{"edge-type", required_argument, 0, 0},
{"group-penalty-a", required_argument, 0, 0},
{"group-penalty-b", required_argument, 0, 0},
{"group-penalty-type", required_argument, 0, 0},
{"group-size", required_argument, 0, 0},
{"group-size-mode", required_argument, 0, 0},
{"group-mode", required_argument, 0, 0},
{0, 0, 0, 0}
};
int opt;
int long_index = 0;
while ((opt = getopt_long(argc, argv, "n:m:k:s:e:v:p:f:", long_options, &long_index)) != -1) {
switch (opt) {
case 'n':
n = (uint32_t)atoi(optarg);
break;
case 'm':
m = (uint64_t)atoll(optarg);
break;
case 'k':
k = (uint16_t)atoi(optarg);
break;
case 's':
seed = (uint16_t)atoi(optarg);
break;
case 'e':
e = optarg;
break;
case 'v':
v = optarg;
break;
case 'p':
p = optarg;
break;
case 'f':
snprintf(filename, sizeof(filename), "%s", optarg);
break;
case 0:
if (strcmp(long_options[long_index].name, "vertex-a") == 0) {
vertex_a = atof(optarg);
} else if (strcmp(long_options[long_index].name, "vertex-b") == 0) {
vertex_b = atof(optarg);
} else if (strcmp(long_options[long_index].name, "vertex-type") == 0) {
vertex_weight_type = optarg;
} else if (strcmp(long_options[long_index].name, "edge-a") == 0) {
edge_a = atof(optarg);
} else if (strcmp(long_options[long_index].name, "edge-b") == 0) {
edge_b = atof(optarg);
} else if (strcmp(long_options[long_index].name, "edge-family") == 0) {
edge_weight_family = optarg;
} else if (strcmp(long_options[long_index].name, "edge-type") == 0) {
edge_weight_type = optarg;
} else if (strcmp(long_options[long_index].name, "group-penalty-a") == 0) {
group_penalty_a = atof(optarg);
} else if (strcmp(long_options[long_index].name, "group-penalty-b") == 0) {
group_penalty_b = atof(optarg);
} else if (strcmp(long_options[long_index].name, "group-penalty-type") == 0) {
group_penalty_type = optarg;
} else if (strcmp(long_options[long_index].name, "group-size") == 0) {
group_size = atoi(optarg);
} else if (strcmp(long_options[long_index].name, "group-size-mode") == 0) {
group_size_mode = optarg;
} else if (strcmp(long_options[long_index].name, "group-mode") == 0) {
snprintf(group_mode, sizeof(group_mode), "%s", optarg);
}
break;
default:
print_usage(argv[0]);
exit(EXIT_FAILURE);
}
}
if (group_size == 1) {
instance_type_per_size = "";
instance_type_code_per_size = "";
} else if (group_size <= 0 || group_size > n){
fprintf(stderr, "Group size is: %d. MUST BE at least 1 and at most n=%d.\n", group_size, n);
exit(EXIT_FAILURE);
}
if (strcmp(e,"yes") == 0 && strcmp(v,"yes")==0 && strcmp(p,"yes")==0){
snprintf(instance_type, sizeof(instance_type), "Prize-Collecting %sSteiner Tree Instance with both edge and node weights", instance_type_per_size);
snprintf(instance_type_code, sizeof(instance_type_code), "PCNWEW%sST", instance_type_code_per_size);
}else if (strcmp(e,"yes") == 0 && strcmp(v,"yes")==0 && strcmp(p,"no")==0){
snprintf(instance_type, sizeof(instance_type), "%sSteiner Tree Instance with both edge and node weights", instance_type_per_size);
snprintf(instance_type_code, sizeof(instance_type_code), "NWEW%sST", instance_type_code_per_size);
}else if (strcmp(e,"yes") == 0 && strcmp(v,"no")==0 && strcmp(p,"yes")==0){
snprintf(instance_type, sizeof(instance_type), "Prize-Collecting %sSteiner Tree Instance", instance_type_per_size);
snprintf(instance_type_code, sizeof(instance_type_code), "PCEW%sST", instance_type_code_per_size);
}else if (strcmp(e,"yes") == 0 && strcmp(v,"no")==0 && strcmp(p,"no")==0){
snprintf(instance_type, sizeof(instance_type), "%sSteiner Tree Instance", instance_type_per_size);
snprintf(instance_type_code, sizeof(instance_type_code), "EW%sST", instance_type_code_per_size);
}else if (strcmp(e,"no") == 0 && strcmp(v,"yes")==0 && strcmp(p,"no")==0){
snprintf(instance_type, sizeof(instance_type), "Node Weighted %sSteiner Tree Instance", instance_type_per_size);
snprintf(instance_type_code, sizeof(instance_type_code), "NW%sST", instance_type_code_per_size);
}else if (strcmp(e,"no") == 0 && strcmp(v,"yes")==0 && strcmp(p,"yes")==0){
snprintf(instance_type, sizeof(instance_type), "Prize-Collecting Node Weighted %sSteiner Tree Instance", instance_type_per_size);
snprintf(instance_type_code, sizeof(instance_type_code), "PCNW%sST", instance_type_code_per_size);
}else if (strcmp(e,"no") == 0 && strcmp(v,"no")==0 && strcmp(p,"yes")==0){
snprintf(instance_type, sizeof(instance_type), "Prize-Collecting Unweighted %sSteiner Tree Instance", instance_type_per_size);
snprintf(instance_type_code, sizeof(instance_type_code), "PCUW%sST", instance_type_code_per_size);
}else{
snprintf(instance_type, sizeof(instance_type), "Unweighted %sSteiner Tree Instance", instance_type_per_size);
snprintf(instance_type_code, sizeof(instance_type_code), "UW%sST", instance_type_code_per_size);
}
generate_random_group_steiner_instance(
n, m, k, filename,
n, m, k, e, v, p, filename,
vertex_a, vertex_b, vertex_weight_type,
edge_a, edge_b, edge_weight_family, edge_weight_type, instance_type, &seed);
edge_a, edge_b, edge_weight_family, edge_weight_type, group_penalty_a, group_penalty_b, group_penalty_type, &group_size, group_size_mode, group_mode, instance_type, instance_type_code, &seed);
printf("Random Group Steiner instance written to %s\n", filename);
printf("Random %s written to %s\n",instance_type, filename);
return 0;
}

View File

@ -19,29 +19,34 @@ float generate_random_edge_weight(float *x, float *y, unsigned int N, unsigned i
exit(EXIT_FAILURE);
}
float weight = 1.0;
float weight = 0.0;
if (strcmp(family, "euclid") == 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) {
} 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) {
} 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);
fprintf(stderr, "Error: Invalid edge weight family '%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);
if(weight < 1.0) weight = 1.0;
}
else if (strcmp(type, "float") == 0){
if(weight < 1e-8) weight = 1e-8;
}
else{
fprintf(stderr, "Error: Invalid edge weight type '%s'. Use 'int' or 'float'.\n", type);
exit(EXIT_FAILURE);
}

View File

@ -10,15 +10,15 @@ int cmpInt(const void *a, const void *b) {
}
inline uint32_t min(uint32_t u, uint32_t v){
inline uint64_t min(uint64_t u, uint64_t v){
return u < v ? u : v;
}
inline uint32_t max(uint32_t u, uint32_t v){
inline uint64_t max(uint64_t u, uint64_t v){
return u < v ? v : u;
}
uint64_t uv2index(uint32_t u, uint32_t v, uint32_t n) {
inline uint64_t uv2index(uint32_t u, uint32_t v, uint32_t n) {
if (u < n && v < n && u < v) {
uint64_t uu = (uint64_t)(u);
uint64_t vv = (uint64_t)(v);
@ -32,18 +32,18 @@ uint64_t uv2index(uint32_t u, uint32_t v, uint32_t n) {
return (uint64_t)(-1);
}
}
fprintf(stderr, "Error: Invalid u or v values.\n");
fprintf(stderr, "Error: Invalid u or v values. u = %u, v = %u, n=%u \n", u, v, n);
return (uint64_t)(-1);
}
int8_t index2uv(uint64_t index, uint32_t n, uint32_t *u, uint32_t *v) {
if (index < (n * (n - 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;
inline int8_t index2uv(uint64_t index, uint32_t n, uint32_t *u, uint32_t *v) {
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 * nn - 1) - sqrt(dd)) / 2;
int64_t vv = uu + index + 1 - uu * (2*nn - uu - 1) / 2;
if (indexx < (nn * (nn - 1)) / 2) {
if (uu >= 0 && uu < n && vv >= uu + 1 && vv < n) {
*u = (uint32_t)uu;
*v = (uint32_t)vv;
@ -62,112 +62,134 @@ int8_t index2uv(uint64_t index, uint32_t n, uint32_t *u, uint32_t *v) {
return -1;
}
void random_connected_graph(
uint32_t n, uint64_t m, Edge *edges, uint16_t* seed) {
inline uint64_t permuted(uint64_t pos, uint64_t a, uint64_t c, uint64_t n) {
return (((uint64_t)a) * ((uint64_t)pos) + (uint64_t)c) % ((uint64_t)n);
}
// Custom binary search function
inline int8_t binarySearch(uint64_t *arr, uint64_t size, uint64_t key) {
int64_t low = 0, high = size - 1;
while (low <= high) {
int64_t mid = low + (high - low) / 2;
if (arr[mid] == key)
return 1; // Key found
if (arr[mid] < key)
low = mid + 1;
else
high = mid - 1;
}
return 0; // Key not found
}
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);
}
uint64_t PRIME_PERM = 5000000029;
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 of arrays N, M or T failed.\n");
free(T);
free(M);
free(N);
uint64_t *T = malloc(m * sizeof(uint64_t)); // Array for selected edge indices
if (!T) {
fprintf(stderr, "Error: Memory allocation failed for array T.\n");
exit(EXIT_FAILURE);
}
// Select coprime multiplier `a`
// uint32_t c = *seed % n; // Random offset
uint32_t c = 0;
// Step 1: Build a spanning tree
for (uint64_t v = 1; v < n; v++) {
uint64_t u = rand_r_large(seed) % v;
uint64_t permutedV = permuted(v, PRIME_PERM, c, n);
uint64_t permutedU = permuted(u, PRIME_PERM, c, n);
if (min(permutedU,permutedV) == max(permutedU,permutedV)){
free(T);
fprintf(stderr, "u and v are not mapped to different indices: u=%lu, v=%lu, min = %lu\n", u, v, min(permutedU,permutedV));
exit(EXIT_FAILURE);
}
}
// Initialize vertex and edge index arrays
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
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 (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);
uint64_t index = uv2index(min(permutedU,permutedV), max(permutedU,permutedV), 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
T[v - 1] = index; // Add spanning tree edge index
}
// Sort the initial edges of the spanning tree
// Sort the first n-1 elements for binary search
qsort(T, n - 1, sizeof(uint64_t), cmpInt);
// put all selected edges back to the array (last n-1 elements of M)
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 (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 (uint64_t i = 0; i < m - n + 1; i++) {
T[n - 1 + i] = M[i];
}
// Sort the entire T array
qsort(T, m, sizeof(uint64_t), cmpInt);
// Convert indices to edges and create the edge array
uint64_t check = m;
for (uint64_t i = 0; i < m; i++) {
uint64_t previous_index = mmax; // Initialize with an invalid index
for (uint64_t i = 0; i < n-1; i++) {
uint32_t u, v;
if (index2uv(T[i], n, &u, &v) == -1) {
free(T);
free(M);
free(N);
exit(EXIT_FAILURE);
}
if (T[i] == check){
fprintf(stderr, "Error: Duplicated edge (%d - %d) found.\n", u, v);
// Check for duplicate edges
if (T[i] == previous_index) {
fprintf(stderr, "ERROR: Duplicate edge (%u, %u) detected, T[i] = %lu, previous_index = %lu.\n", u, v, T[i], previous_index);
free(T);
exit(EXIT_FAILURE);
}
check = T[i];
previous_index = T[i];
// edges[i].src = u;
// edges[i].dest = v;
}
// Step 2: Add additional edges
uint64_t additional_edges_added = 0;
// uint64_t current = 0;
for (uint64_t i = 0; i < mmax && additional_edges_added < m - n + 1; i++) {
uint64_t permutedIndex = permuted(i, PRIME_PERM, c, mmax);
// Check if the edge index is already in the spanning tree
if (binarySearch(T, n - 1, permutedIndex)) {
continue; // Edge already exists in the tree
}
// Add the edge index to T after n-1 elements
T[n - 1 + additional_edges_added] = permutedIndex;
additional_edges_added++;
}
// Verify enough edges were added
if (additional_edges_added != m - n + 1) {
fprintf(stderr, "Error: Could not generate the required number of edges.\n");
free(T);
exit(EXIT_FAILURE);
}
// c = *seed % mmax;
c = 0;
// Step 3: Sort the entire T array
qsort(T, m, sizeof(uint64_t), cmpInt);
// Step 4: Convert edge indices to actual edges
previous_index = mmax; // Initialize with an invalid index
for (uint64_t i = 0; i < m; i++) {
uint32_t u, v;
if (index2uv(T[i], n, &u, &v) == -1) {
free(T);
exit(EXIT_FAILURE);
}
// Check for duplicate edges
if (T[i] == previous_index) {
fprintf(stderr, "Error: Duplicate edge (%u, %u) detected, T[i] = %lu, previous_index = %lu.\n", u, v, T[i], previous_index);
free(T);
exit(EXIT_FAILURE);
}
previous_index = T[i];
edges[i].src = u;
edges[i].dest = v;
}
// Output edges
// Cleanup
// Free dynamically allocated memory
free(T);
free(M);
free(N);
}

View File

@ -8,22 +8,17 @@
#include "random_vertex_weight.h"
void generate_random_group_steiner_instance(
uint32_t n, uint32_t m, uint16_t k, const char *filename,
uint32_t n, uint64_t m, uint16_t k, const char* e, const char* v, const char* p, 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) {
float edge_a, float edge_b, const char *edge_weight_family, const char *edge_weight_type, float group_penalty_a, float group_penalty_b, const char* group_penalty_type, uint32_t* group_size, const char* group_size_mode, char* group_mode, const char *instance_type, const char* instance_type_code, 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);
@ -34,7 +29,6 @@ void generate_random_group_steiner_instance(
if (!x) {
fprintf(stderr, "Error: Memory allocation failed for array x.\n");
free(edges);
fclose(file);
exit(EXIT_FAILURE);
}
@ -43,7 +37,6 @@ void generate_random_group_steiner_instance(
fprintf(stderr, "Error: Memory allocation failed for array y.\n");
free(x);
free(edges);
fclose(file);
exit(EXIT_FAILURE);
}
@ -75,38 +68,93 @@ void generate_random_group_steiner_instance(
}
}
// Generate random groups
generate_random_groups(n, k, groups, seed);
generate_random_groups(n, k, groups, group_size, group_size_mode, group_mode, seed);
if (strcmp(filename,"") == 0) {
snprintf(filename, 256, "DWW_%s_%s_n=%u_m=%lu_k=%u_s=%u_vwt=%s_vwl=%.1f_vwu=%.1f_ewt=%s_gs=%u_gsm=%s_gm=%s.stp",
instance_type_code,edge_weight_family, n, m, k, (uint32_t)*seed, vertex_weight_type, vertex_a, vertex_b, edge_weight_type, *group_size, group_size_mode, group_mode);
}
// 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);
}
// 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, "DWW_%s_%s_n=%u_m=%lu_k=%u_s=%u_vwt=%s_vwl=%.1f_vwu=%.1f_ewt=%s_gs=%u_gsm=%s_gm=%s\n", instance_type_code,edge_weight_family, n, m, k, (uint32_t)*seed, vertex_weight_type, vertex_a, vertex_b, edge_weight_type, *group_size, group_size_mode, group_mode);
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);
fprintf(file, "Edges %lu\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);
if (strcmp(v,"yes") == 0 && strcmp(vertex_weight_type,"int") == 0) {
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);
}
} else if (strcmp(v,"yes") == 0 && strcmp(vertex_weight_type,"float") == 0) {
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 %.9f\n", vertex_weight);
}
}
if (strcmp(e, "yes") == 0 && strcmp(edge_weight_type,"int") == 0){
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 %.1f\n", edges[i].src, edges[i].dest, edge_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);
} else if (strcmp(e, "yes") == 0 && strcmp(edge_weight_type,"float") == 0) {
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 %.9f\n", edges[i].src, edges[i].dest, edge_weight);
}
} else if (strcmp(e, "no") == 0) {
for (unsigned int i = 0; i < m; i++) {
fprintf(file, "E %d %d\n", edges[i].src, edges[i].dest);
}
}
fprintf(file, "END\n\n");
// Write the terminals section
fprintf(file, "SECTION Terminals\n");
fprintf(file, "Terminals %u\n", k);
// Write group penalties
if (strcmp(p,"yes") == 0 && strcmp(group_penalty_type,"int") == 0) {
for (unsigned int i = 0; i < k; i++) {
float group_penalty = generate_random_vertex_weight(group_penalty_type, group_penalty_a, group_penalty_b, seed);
fprintf(file, "P %.1f\n", group_penalty);
}
} else if (strcmp(p,"yes") == 0 && strcmp(group_penalty_type,"float") == 0) {
for (unsigned int i = 0; i < k; i++) {
float group_penalty = generate_random_vertex_weight(group_penalty_type, group_penalty_a, group_penalty_b, seed);
fprintf(file, "P %.9f\n", group_penalty);
}
}
for (unsigned int i = 0; i < k; i++) {
fprintf(file, "T");
for (unsigned int j = 0; j < groups[i].size; j++) {

View File

@ -1,5 +1,17 @@
#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) {
@ -12,7 +24,7 @@ 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) {
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);
@ -61,18 +73,68 @@ void generate_random_groups(uint32_t n, uint16_t k, Group *groups, uint16_t* see
groups[i].group[groups[i].size++] = N[offset + i];
}
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]];
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);
}
// Sort each group
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), cmpInt);
qsort(groups[i].group, groups[i].size, sizeof(uint32_t), cmpGroups);
}
// Clean up

View File

@ -6,15 +6,18 @@ float generate_random_vertex_weight(const char *weight_type, float a, float b, u
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);
float random_value = 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);
if (strcmp(weight_type, "int") == 0) {
if(random_value < 1.0) random_value = 1.0;
random_value = (float)((int)random_value);
} else if (strcmp(weight_type, "float") == 0) {
return random_value;
if(random_value < 1e-8) random_value = 1e-8;
} else {
fprintf(stderr, "Error: Invalid weight type '%s'. Use 'integer' or 'float'.\n", weight_type);
fprintf(stderr, "Error: Invalid vertex weight type '%s'. Use 'int' or 'float'.\n", weight_type);
exit(EXIT_FAILURE);
}
return random_value;
}