add generation of data for harvensine
This commit is contained in:
parent
efa6a8b205
commit
97be659f53
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
build
|
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"inttypes.h": "c",
|
||||||
|
"errno.h": "c"
|
||||||
|
}
|
||||||
|
}
|
12
Makefile
Normal file
12
Makefile
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
CFLAGS=-g -Wall
|
||||||
|
|
||||||
|
.PHONY := gen_data
|
||||||
|
|
||||||
|
gen_data: build/gen_data.exe
|
||||||
|
|
||||||
|
build/gen_data.exe: src/gen_data.c
|
||||||
|
mkdir -p build
|
||||||
|
gcc -o build/gen_data.exe src/gen_data.c $(CFLAGS) -O2
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -r build
|
256
src/gen_data.c
Normal file
256
src/gen_data.c
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define EARTH_RADIUS 6372.8
|
||||||
|
#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0]))
|
||||||
|
#define strequal(a, b) !strcmp(a, b)
|
||||||
|
|
||||||
|
typedef float f32;
|
||||||
|
typedef double f64;
|
||||||
|
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
typedef uint64_t u64;
|
||||||
|
|
||||||
|
enum gen_method {
|
||||||
|
GEN_UNIFORM,
|
||||||
|
GEN_CLUSTER
|
||||||
|
};
|
||||||
|
|
||||||
|
static u8 rand_u8() {
|
||||||
|
return rand() & 0xFF;
|
||||||
|
}
|
||||||
|
static u16 rand_u16() {
|
||||||
|
return rand_u8() | (rand_u8() << 8);
|
||||||
|
}
|
||||||
|
static u32 rand_u32() {
|
||||||
|
return rand_u16() | (rand_u16() << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/55766267
|
||||||
|
static f64 rand_f64() {
|
||||||
|
u64 r53 = ((uint64_t)(rand_u32()) << 21) ^ (rand_u8() >> 2);
|
||||||
|
return (double)r53 / 9007199254740991.0; // 2^53 - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
static f64 rand_f64_range(f64 from, f64 to) {
|
||||||
|
return rand_f64() * (to - from) + from;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 rand_u32_range(u32 from, u32 to) {
|
||||||
|
return rand_u32() % (to - from + 1) + from;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_json_f64(char *key, f64 value, FILE *stream) {
|
||||||
|
char buffer[256];
|
||||||
|
int size = snprintf(buffer, sizeof(buffer), "\"%s\":%21.16f", key, value);
|
||||||
|
fwrite(buffer, sizeof(char), size, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static f64 sqaure_f64(f64 num)
|
||||||
|
{
|
||||||
|
return num*num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static f64 radians_to_degrees(f64 degrees)
|
||||||
|
{
|
||||||
|
return 0.01745329251994329577 * degrees;
|
||||||
|
}
|
||||||
|
|
||||||
|
static f64 get_harvensine_distance(f64 X0, f64 Y0, f64 X1, f64 Y1, f64 earth_radius)
|
||||||
|
{
|
||||||
|
f64 lat1 = Y0;
|
||||||
|
f64 lat2 = Y1;
|
||||||
|
f64 lon1 = X0;
|
||||||
|
f64 lon2 = X1;
|
||||||
|
|
||||||
|
f64 dLat = radians_to_degrees(lat2 - lat1);
|
||||||
|
f64 dLon = radians_to_degrees(lon2 - lon1);
|
||||||
|
lat1 = radians_to_degrees(lat1);
|
||||||
|
lat2 = radians_to_degrees(lat2);
|
||||||
|
|
||||||
|
f64 a = sqaure_f64(sin(dLat/2.0)) + cos(lat1)*cos(lat2)*sqaure_f64(sin(dLon/2));
|
||||||
|
f64 c = 2.0*asin(sqrt(a));
|
||||||
|
|
||||||
|
return earth_radius * c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t find_filename_ext(const char *filename, size_t length) {
|
||||||
|
for (size_t i = length-1; i >= 0; i--) {
|
||||||
|
if (filename[i] == '.') {
|
||||||
|
return i+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *replace_filename_ext(const char *filename, const char *ext) {
|
||||||
|
size_t length = strlen(filename);
|
||||||
|
char *new_filename = calloc(strlen(filename)+strlen(ext)+1, sizeof(char));
|
||||||
|
strcpy(new_filename, filename);
|
||||||
|
size_t extension_idx = find_filename_ext(filename, length);
|
||||||
|
strcpy(new_filename+extension_idx, ext);
|
||||||
|
return new_filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool does_ext_match(const char *filename, const char *ext) {
|
||||||
|
size_t ext_idx = find_filename_ext(filename, strlen(filename));
|
||||||
|
if (ext_idx == -1) return false;
|
||||||
|
return strequal(filename + ext_idx, ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_json_start(FILE *f) {
|
||||||
|
fwrite("{\"pairs\":[\n", sizeof(char), 11, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_json_end(FILE *f) {
|
||||||
|
fwrite("]}", sizeof(char), 2, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_json_row(f64 x0, f64 y0, f64 x1, f64 y1, bool is_last, FILE *f) {
|
||||||
|
fwrite("\t{", sizeof(char), 2, f);
|
||||||
|
|
||||||
|
write_json_f64("x0", x0, f);
|
||||||
|
fwrite(", ", sizeof(char), 2, f);
|
||||||
|
write_json_f64("y0", y0, f);
|
||||||
|
fwrite(", ", sizeof(char), 2, f);
|
||||||
|
write_json_f64("x1", x1, f);
|
||||||
|
fwrite(", ", sizeof(char), 2, f);
|
||||||
|
write_json_f64("y1", y1, f);
|
||||||
|
|
||||||
|
fwrite("}", sizeof(char), 1, f);
|
||||||
|
if (!is_last) {
|
||||||
|
fwrite(",", sizeof(char), 1, f);
|
||||||
|
}
|
||||||
|
fwrite("\n", sizeof(char), 1, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_usage(char *program) {
|
||||||
|
fprintf(stderr, "Usage: %s <command>\n", program);
|
||||||
|
fprintf(stderr, "Commands:\n");
|
||||||
|
fprintf(stderr, "\tuniform <size> <json-output-file> [seed]\n");
|
||||||
|
fprintf(stderr, "\tcluster <size> <json-output-file> [seed]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
if (argc < 2) {
|
||||||
|
print_usage(argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 row_count;
|
||||||
|
char *json_output;
|
||||||
|
u32 seed = time(NULL);
|
||||||
|
char *method_name = argv[1];
|
||||||
|
enum gen_method method;
|
||||||
|
if (strequal(method_name, "uniform")) {
|
||||||
|
if (argc < 4) {
|
||||||
|
print_usage(argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
row_count = atoi(argv[2]);
|
||||||
|
json_output = argv[3];
|
||||||
|
|
||||||
|
if (argc >= 5) {
|
||||||
|
seed = atoi(argv[4]);
|
||||||
|
}
|
||||||
|
method = GEN_UNIFORM;
|
||||||
|
} else if (strequal(method_name, "cluster")) {
|
||||||
|
if (argc < 4) {
|
||||||
|
print_usage(argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
row_count = atoi(argv[2]);
|
||||||
|
json_output = argv[3];
|
||||||
|
|
||||||
|
if (argc >= 5) {
|
||||||
|
seed = atoi(argv[4]);
|
||||||
|
}
|
||||||
|
method = GEN_CLUSTER;
|
||||||
|
} else {
|
||||||
|
print_usage(argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!does_ext_match(json_output, "json")) {
|
||||||
|
fprintf(stderr, "ERROR: Expected json file to end with .json\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *json_file = fopen(json_output, "w");
|
||||||
|
if (json_file == NULL) {
|
||||||
|
fprintf(stderr, "Failed to open file '%s' for writting: %s\n", json_output, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *answer_output = replace_filename_ext(json_output, "bin");
|
||||||
|
FILE *answer_file = fopen(answer_output, "w");
|
||||||
|
if (json_file == NULL) {
|
||||||
|
fprintf(stderr, "Failed to open file '%s' for writting: %s\n", answer_output, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
srand(seed);
|
||||||
|
f64 sum = 0;
|
||||||
|
if (method == GEN_UNIFORM) {
|
||||||
|
write_json_start(json_file);
|
||||||
|
for (size_t i = 0; i < row_count; i++) {
|
||||||
|
f64 x0 = rand_f64_range(-180, 180);
|
||||||
|
f64 y0 = rand_f64_range(-90, 90);
|
||||||
|
f64 x1 = rand_f64_range(-180, 180);
|
||||||
|
f64 y1 = rand_f64_range(-90, 90);
|
||||||
|
|
||||||
|
f64 distance = get_harvensine_distance(x0, y0, x1, y1, EARTH_RADIUS);
|
||||||
|
sum += distance;
|
||||||
|
|
||||||
|
write_json_row(x0, y0, x1, y1, i == row_count-1, json_file);
|
||||||
|
fwrite(&distance, sizeof(f64), 1, answer_file);
|
||||||
|
}
|
||||||
|
write_json_end(json_file);
|
||||||
|
} else if (method == GEN_CLUSTER) {
|
||||||
|
u32 cluster_count = 32; // TODO: Make this configurable
|
||||||
|
f64 cluster_x_range = 180.0 / 15.0;
|
||||||
|
f64 cluster_y_range = 90.0 / 15.0;
|
||||||
|
|
||||||
|
f64 *clusters_x = malloc(cluster_count * sizeof(f64));
|
||||||
|
f64 *clusters_y = malloc(cluster_count * sizeof(f64));
|
||||||
|
for (size_t i = 0; i < cluster_count; i++) {
|
||||||
|
clusters_x[i] = rand_f64_range(-180, 180);
|
||||||
|
clusters_x[i] = rand_f64_range(-90, 90);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_json_start(json_file);
|
||||||
|
for (size_t i = 0; i < row_count; i++) {
|
||||||
|
u32 from_cluster = rand_u32_range(0, cluster_count-1);
|
||||||
|
u32 to_cluster = rand_u32_range(0, cluster_count-1);
|
||||||
|
|
||||||
|
f64 x0 = clusters_x[from_cluster] + rand_f64_range(-cluster_x_range, cluster_x_range);
|
||||||
|
f64 y0 = clusters_y[from_cluster] + rand_f64_range(-cluster_y_range, cluster_y_range);
|
||||||
|
f64 x1 = clusters_x[to_cluster] + rand_f64_range(-cluster_x_range, cluster_x_range);
|
||||||
|
f64 y1 = clusters_y[to_cluster] + rand_f64_range(-cluster_y_range, cluster_y_range);
|
||||||
|
|
||||||
|
f64 distance = get_harvensine_distance(x0, y0, x1, y1, EARTH_RADIUS);
|
||||||
|
sum += distance;
|
||||||
|
|
||||||
|
write_json_row(x0, y0, x1, y1, i == row_count-1, json_file);
|
||||||
|
fwrite(&distance, sizeof(f64), 1, answer_file);
|
||||||
|
}
|
||||||
|
write_json_end(json_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(&sum, sizeof(f64), 1, answer_file);
|
||||||
|
|
||||||
|
printf("Used earth radius: %f\n", EARTH_RADIUS);
|
||||||
|
printf("Seed: %d\n", seed);
|
||||||
|
printf("Number of pairs: %d\n", row_count);
|
||||||
|
printf("Expected sum: %lf\n", sum);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user