refactor: ♻️ Only spaces and format fixed.

This commit is contained in:
Слободан Јелић 2025-10-10 10:36:31 +00:00
parent 1754f6cf91
commit e0340eaf9e
13 changed files with 966 additions and 896 deletions

View File

@ -1,17 +1,17 @@
#ifndef RAND_R_LARGE_H
#define RAND_R_LARGE_H
#include <stdint.h>
/**
* 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
#ifndef RAND_R_LARGE_H
#define RAND_R_LARGE_H
#include <stdint.h>
/**
* 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

View File

@ -1,14 +1,14 @@
#ifndef GEOMETRY_WEIGHTS_H
#define GEOMETRY_WEIGHTS_H
#include <stdlib.h>
#include <stdint.h>
// 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
#ifndef GEOMETRY_WEIGHTS_H
#define GEOMETRY_WEIGHTS_H
#include <stdlib.h>
#include <stdint.h>
// 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

View File

@ -1,30 +1,30 @@
#ifndef RANDOM_GRAPH_H
#define RANDOM_GRAPH_H
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
#include "rand_large.h"
// Edge structure
typedef struct Edge {
uint32_t src;
uint32_t dest;
} 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);
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);
#endif // RANDOM_GRAPH_H
#ifndef RANDOM_GRAPH_H
#define RANDOM_GRAPH_H
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
#include "rand_large.h"
// Edge structure
typedef struct Edge {
uint32_t src;
uint32_t dest;
} 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);
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);
#endif // RANDOM_GRAPH_H

View File

@ -1,13 +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, 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, 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
#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, 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, 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

@ -1,18 +1,18 @@
#ifndef RANDOM_GROUPS_H
#define RANDOM_GROUPS_H
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
// Struct for representing groups
typedef struct {
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 shuffle(uint32_t *array, uint32_t size, 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
#ifndef RANDOM_GROUPS_H
#define RANDOM_GROUPS_H
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
// Struct for representing groups
typedef struct {
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 shuffle(uint32_t *array, uint32_t size, 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,12 +1,12 @@
#ifndef RANDOM_VERTEX_WEIGHT_H
#define RANDOM_VERTEX_WEIGHT_H
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <stdint.h>
// 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
#ifndef RANDOM_VERTEX_WEIGHT_H
#define RANDOM_VERTEX_WEIGHT_H
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <stdint.h>
// 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

View File

@ -1,186 +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(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;
char filename[256] = "";
float vertex_a = 1.0, vertex_b = 10.0;
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 = "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, e, v, p, filename,
vertex_a, vertex_b, vertex_weight_type,
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 %s written to %s\n",instance_type, filename);
return 0;
}
#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(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;
char filename[256] = "";
float vertex_a = 1.0, vertex_b = 10.0;
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 = "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, e, v, p, filename,
vertex_a, vertex_b, vertex_weight_type,
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 %s written to %s\n",instance_type, filename);
return 0;
}

View File

@ -1,12 +1,12 @@
#include <stdint.h>
#include <stdlib.h>
#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;
}
#include <stdint.h>
#include <stdlib.h>
#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;
}

View File

@ -1,54 +1,54 @@
#include "random_edge_weight.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
// 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 = 0.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 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);
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);
}
return weight;
}
#include "random_edge_weight.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
// 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 = 0.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 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);
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);
}
return weight;
}

View File

@ -1,195 +1,243 @@
#include "random_graph.h"
int cmpInt(const void *a, const void *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 uint64_t min(uint64_t u, uint64_t v){
return u < v ? u : v;
}
inline uint64_t max(uint64_t u, uint64_t v){
return u < v ? v : u;
}
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);
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 (uint64_t)(-1);
}
}
fprintf(stderr, "Error: Invalid u or v values. u = %u, v = %u, n=%u \n", u, v, n);
return (uint64_t)(-1);
}
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;
return 0;
} else {
// 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;
}
}
fprintf(stderr, "Error: Invalid edge index. Must be less than n(n-1)/2.\n");
return -1;
}
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
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);
}
uint64_t index = uv2index(min(permutedU,permutedV), max(permutedU,permutedV), n);
if (index == (uint64_t)(-1)) {
free(T);
exit(EXIT_FAILURE);
}
T[v - 1] = index; // Add spanning tree edge index
}
// Sort the first n-1 elements for binary search
qsort(T, n - 1, sizeof(uint64_t), cmpInt);
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);
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;
}
// 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;
}
// Free dynamically allocated memory
free(T);
}
#include "random_graph.h"
int cmpInt(const void *a, const void *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 uint64_t min(uint64_t u, uint64_t v)
{
return u < v ? u : v;
}
inline uint64_t max(uint64_t u, uint64_t v)
{
return u < v ? v : u;
}
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);
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 (uint64_t)(-1);
}
}
fprintf(stderr, "Error: Invalid u or v values. u = %u, v = %u, n=%u \n", u, v, n);
return (uint64_t)(-1);
}
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;
return 0;
}
else
{
// 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;
}
}
fprintf(stderr, "Error: Invalid edge index. Must be less than n(n-1)/2.\n");
return -1;
}
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
}
/**
* @brief Generates a random connected graph with the specified number of nodes and edges.
*
* This function creates a random connected graph with `n` nodes and `m` edges.
* The edges of the graph are stored in the provided `edges` array. The graph
* generation process uses the given `seed` for randomization, ensuring
* reproducibility of the generated graph.
*
* @param n The number of nodes in the graph.
* @param m The number of edges in the graph.
* @param edges Pointer to an array where the generated edges will be stored.
* The array should be pre-allocated with a size of at least `m`.
* @param seed Pointer to a 16-bit seed value used for random number generation.
* The seed is updated during the graph generation process.
*/
void random_connected_graph(uint32_t n, uint64_t m, Edge *edges, uint16_t *seed)
{
if (seed == NULL)
{
fprintf(stderr, "Error: Seed parameter is NULL.\n");
exit(EXIT_FAILURE);
}
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
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);
}
uint64_t index = uv2index(min(permutedU, permutedV), max(permutedU, permutedV), n);
if (index == (uint64_t)(-1))
{
free(T);
exit(EXIT_FAILURE);
}
T[v - 1] = index; // Add spanning tree edge index
}
// Sort the first n-1 elements for binary search
qsort(T, n - 1, sizeof(uint64_t), cmpInt);
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);
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;
}
// 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;
}
// Free dynamically allocated memory
free(T);
}

View File

@ -1,179 +1,179 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#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, 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, 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) {
// Generate a random connected graph
Edge *edges = (Edge *)malloc(m * sizeof(Edge));
if (!edges) {
fprintf(stderr, "Error: Memory allocation failed for edges.\n");
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);
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);
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, 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, "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 %lu\n", m);
// Write vertex weights
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);
}
} 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++) {
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);
}
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#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, 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, 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) {
// Generate a random connected graph
Edge *edges = (Edge *)malloc(m * sizeof(Edge));
if (!edges) {
fprintf(stderr, "Error: Memory allocation failed for edges.\n");
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);
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);
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, 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, "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 %lu\n", m);
// Write vertex weights
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);
}
} 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++) {
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);
}

View File

@ -1,143 +1,165 @@
#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);
}
#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
/**
* @brief Shuffles the elements of an array of uint32_t in place.
*
* This function randomly permutes the elements of the given array using the provided seed.
*
* @param array Pointer to the array of uint32_t to be shuffled.
* @param size Number of elements in the array.
* @param seed Pointer to a uint16_t value used as the seed for randomization.
*/
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;
}
}
/**
* @brief Generates random groups from a set of elements.
*
* This function divides `n` elements into `k` groups according to the specified modes.
*
* @param n Number of elements to be grouped.
* @param k Number of groups to generate.
* @param groups Pointer to an array of Group structures where the generated groups will be stored.
* @param group_size Pointer to an array where the size of each group will be stored.
* @param group_size_mode String specifying the mode for determining group sizes (e.g., "equal", "random").
* @param group_mode String specifying the grouping mode (e.g., "sequential", "random").
* @param seed Pointer to a seed value for random number generation.
*/
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);
}

View File

@ -1,23 +1,23 @@
#include "random_vertex_weight.h"
#include <stdio.h>
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 = a + ((float)rand_r((unsigned int* )seed) / RAND_MAX) * (b - a);
// Check the weight type and cast appropriately
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) {
if(random_value < 1e-8) random_value = 1e-8;
} else {
fprintf(stderr, "Error: Invalid vertex weight type '%s'. Use 'int' or 'float'.\n", weight_type);
exit(EXIT_FAILURE);
}
return random_value;
}
#include "random_vertex_weight.h"
#include <stdio.h>
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 = a + ((float)rand_r((unsigned int* )seed) / RAND_MAX) * (b - a);
// Check the weight type and cast appropriately
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) {
if(random_value < 1e-8) random_value = 1e-8;
} else {
fprintf(stderr, "Error: Invalid vertex weight type '%s'. Use 'int' or 'float'.\n", weight_type);
exit(EXIT_FAILURE);
}
return random_value;
}