second working, with arg parser, optimized, group creation is unoptimized
This commit is contained in:
parent
c7fd378336
commit
fe6463fd00
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -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"
|
||||
}
|
||||
}
|
4
Makefile
4
Makefile
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
pandas
|
189
src/main.c
189
src/main.c
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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++) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user