refactor: ♻️ Only spaces and format fixed.
This commit is contained in:
parent
1754f6cf91
commit
e0340eaf9e
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
372
src/main.c
372
src/main.c
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user