1
0

add generation of data for harvensine

This commit is contained in:
Rokas Puzonas 2023-05-28 14:27:07 +03:00
parent efa6a8b205
commit 97be659f53
4 changed files with 275 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
build

6
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,6 @@
{
"files.associations": {
"inttypes.h": "c",
"errno.h": "c"
}
}

12
Makefile Normal file
View 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
View 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;
}