squiggle.c/test/test.c

329 lines
9.1 KiB
C
Raw Permalink Normal View History

2023-07-23 10:41:05 +00:00
#include "../squiggle.h"
#include <math.h>
2023-07-23 13:44:22 +00:00
#include <stdint.h>
2023-07-23 10:41:05 +00:00
#include <stdio.h>
2023-07-23 13:44:22 +00:00
#include <stdlib.h>
2023-07-23 10:41:05 +00:00
2023-07-23 14:28:44 +00:00
#define TOLERANCE 5.0 / 1000.0
2023-07-23 12:00:14 +00:00
#define MAX_NAME_LENGTH 500
2023-07-23 10:41:05 +00:00
2023-07-23 12:00:14 +00:00
// Structs
2023-07-23 10:41:05 +00:00
2023-07-23 12:00:14 +00:00
struct array_expectations {
2023-07-23 13:44:22 +00:00
double* array;
int n;
char* name;
double expected_mean;
double expected_std;
double tolerance;
2023-07-23 12:00:14 +00:00
};
2023-07-23 13:44:22 +00:00
void test_array_expectations(struct array_expectations e)
{
double mean = array_mean(e.array, e.n);
double delta_mean = mean - e.expected_mean;
double std = array_std(e.array, e.n);
double delta_std = std - e.expected_std;
2023-07-23 14:28:44 +00:00
if ((fabs(delta_mean) / fabs(mean) > e.tolerance) && (fabs(delta_mean) > e.tolerance)) {
2023-07-23 13:44:22 +00:00
printf("[-] Mean test for %s NOT passed.\n", e.name);
printf("Mean of %s: %f, vs expected mean: %f\n", e.name, mean, e.expected_mean);
printf("delta: %f, relative delta: %f\n", delta_mean, delta_mean / fabs(mean));
} else {
printf("[x] Mean test for %s PASSED\n", e.name);
}
2023-07-23 14:28:44 +00:00
if ((fabs(delta_std) / fabs(std) > e.tolerance) && (fabs(delta_std) > e.tolerance)) {
2023-07-23 13:44:22 +00:00
printf("[-] Std test for %s NOT passed.\n", e.name);
printf("Std of %s: %f, vs expected std: %f\n", e.name, std, e.expected_std);
printf("delta: %f, relative delta: %f\n", delta_std, delta_std / fabs(std));
} else {
printf("[x] Std test for %s PASSED\n", e.name);
}
printf("\n");
2023-07-23 10:41:05 +00:00
}
2023-07-23 12:00:14 +00:00
// Test unit uniform
2023-07-23 13:44:22 +00:00
void test_unit_uniform(uint64_t* seed)
{
int n = 1000 * 1000;
double* unit_uniform_array = malloc(sizeof(double) * n);
for (int i = 0; i < n; i++) {
unit_uniform_array[i] = sample_unit_uniform(seed);
}
struct array_expectations expectations = {
.array = unit_uniform_array,
.n = n,
.name = "unit uniform",
.expected_mean = 0.5,
.expected_std = sqrt(1.0 / 12.0),
2023-07-23 14:28:44 +00:00
.tolerance = TOLERANCE,
2023-07-23 13:44:22 +00:00
};
test_array_expectations(expectations);
free(unit_uniform_array);
2023-07-23 12:00:14 +00:00
}
// Test uniforms
2023-07-23 13:44:22 +00:00
void test_uniform(double start, double end, uint64_t* seed)
{
int n = 1000 * 1000;
double* uniform_array = malloc(sizeof(double) * n);
for (int i = 0; i < n; i++) {
uniform_array[i] = sample_uniform(start, end, seed);
}
char* name = malloc(MAX_NAME_LENGTH * sizeof(char));
snprintf(name, MAX_NAME_LENGTH, "[%f, %f] uniform", start, end);
struct array_expectations expectations = {
.array = uniform_array,
.n = n,
.name = name,
.expected_mean = (start + end) / 2,
.expected_std = sqrt(1.0 / 12.0) * fabs(end - start),
2023-07-23 14:28:44 +00:00
.tolerance = fabs(end - start) * TOLERANCE,
2023-07-23 13:44:22 +00:00
};
test_array_expectations(expectations);
free(name);
free(uniform_array);
2023-07-23 12:00:14 +00:00
}
// Test unit normal
2023-07-23 13:44:22 +00:00
void test_unit_normal(uint64_t* seed)
{
int n = 1000 * 1000;
double* unit_normal_array = malloc(sizeof(double) * n);
for (int i = 0; i < n; i++) {
unit_normal_array[i] = sample_unit_normal(seed);
}
struct array_expectations expectations = {
.array = unit_normal_array,
.n = n,
.name = "unit normal",
.expected_mean = 0,
.expected_std = 1,
2023-07-23 14:28:44 +00:00
.tolerance = TOLERANCE,
2023-07-23 13:44:22 +00:00
};
test_array_expectations(expectations);
free(unit_normal_array);
2023-07-23 12:00:14 +00:00
}
// Test normal
2023-07-23 13:44:22 +00:00
void test_normal(double mean, double std, uint64_t* seed)
{
int n = 10 * 1000 * 1000;
double* normal_array = malloc(sizeof(double) * n);
for (int i = 0; i < n; i++) {
normal_array[i] = sample_normal(mean, std, seed);
}
char* name = malloc(MAX_NAME_LENGTH * sizeof(char));
snprintf(name, MAX_NAME_LENGTH, "normal(%f, %f)", mean, std);
struct array_expectations expectations = {
.array = normal_array,
.n = n,
.name = name,
.expected_mean = mean,
.expected_std = std,
2023-07-23 14:28:44 +00:00
.tolerance = TOLERANCE,
2023-07-23 13:44:22 +00:00
};
test_array_expectations(expectations);
free(name);
free(normal_array);
}
// Test lognormal
2023-07-23 13:44:22 +00:00
void test_lognormal(double logmean, double logstd, uint64_t* seed)
{
int n = 10 * 1000 * 1000;
double* lognormal_array = malloc(sizeof(double) * n);
for (int i = 0; i < n; i++) {
lognormal_array[i] = sample_lognormal(logmean, logstd, seed);
}
char* name = malloc(MAX_NAME_LENGTH * sizeof(char));
snprintf(name, MAX_NAME_LENGTH, "lognormal(%f, %f)", logmean, logstd);
struct array_expectations expectations = {
.array = lognormal_array,
.n = n,
.name = name,
.expected_mean = exp(logmean + pow(logstd, 2) / 2),
.expected_std = sqrt((exp(pow(logstd, 2)) - 1) * exp(2 * logmean + pow(logstd, 2))),
2023-07-23 14:28:44 +00:00
.tolerance = TOLERANCE,
};
test_array_expectations(expectations);
free(name);
free(lognormal_array);
}
// Test lognormal to
void test_to(double low, double high, uint64_t* seed)
{
int n = 10 * 1000 * 1000;
double* lognormal_array = malloc(sizeof(double) * n);
for (int i = 0; i < n; i++) {
lognormal_array[i] = sample_to(low, high, seed);
}
char* name = malloc(MAX_NAME_LENGTH * sizeof(char));
snprintf(name, MAX_NAME_LENGTH, "to(%f, %f)", low, high);
const double NORMAL95CONFIDENCE = 1.6448536269514722;
double loglow = logf(low);
double loghigh = logf(high);
double logmean = (loglow + loghigh) / 2;
double logstd = (loghigh - loglow) / (2.0 * NORMAL95CONFIDENCE);
struct array_expectations expectations = {
.array = lognormal_array,
.n = n,
.name = name,
.expected_mean = exp(logmean + pow(logstd, 2) / 2),
.expected_std = sqrt((exp(pow(logstd, 2)) - 1) * exp(2 * logmean + pow(logstd, 2))),
.tolerance = TOLERANCE,
2023-07-23 13:44:22 +00:00
};
test_array_expectations(expectations);
free(name);
free(lognormal_array);
2023-07-23 12:00:14 +00:00
}
2023-07-23 12:00:14 +00:00
// Test beta
2023-07-23 13:44:22 +00:00
void test_beta(double a, double b, uint64_t* seed)
{
int n = 10 * 1000 * 1000;
double* beta_array = malloc(sizeof(double) * n);
for (int i = 0; i < n; i++) {
beta_array[i] = sample_beta(a, b, seed);
}
char* name = malloc(MAX_NAME_LENGTH * sizeof(char));
snprintf(name, MAX_NAME_LENGTH, "beta(%f, %f)", a, b);
struct array_expectations expectations = {
.array = beta_array,
.n = n,
.name = name,
.expected_mean = a / (a + b),
.expected_std = sqrt((a * b) / (pow(a + b, 2) * (a + b + 1))),
2023-07-23 14:28:44 +00:00
.tolerance = TOLERANCE,
2023-07-23 13:44:22 +00:00
};
test_array_expectations(expectations);
free(name);
2023-07-23 10:41:05 +00:00
}
2023-07-23 13:44:22 +00:00
int main()
{
2023-07-23 10:41:05 +00:00
// set randomness seed
2023-07-23 10:47:47 +00:00
uint64_t* seed = malloc(sizeof(uint64_t));
2023-07-23 10:41:05 +00:00
*seed = 1000; // xorshift can't start with a seed of 0
2023-07-23 13:44:22 +00:00
printf("Testing unit uniform\n");
test_unit_uniform(seed);
printf("Testing small uniforms\n");
for (int i = 0; i < 100; i++) {
double start = sample_uniform(-10, 10, seed);
double end = sample_uniform(-10, 10, seed);
if (end > start) {
test_uniform(start, end, seed);
}
}
printf("Testing wide uniforms\n");
for (int i = 0; i < 100; i++) {
double start = sample_uniform(-1000 * 1000, 1000 * 1000, seed);
double end = sample_uniform(-1000 * 1000, 1000 * 1000, seed);
if (end > start) {
test_uniform(start, end, seed);
}
}
printf("Testing unit normal\n");
test_unit_normal(seed);
printf("Testing small normals\n");
for (int i = 0; i < 100; i++) {
double mean = sample_uniform(-10, 10, seed);
double std = sample_uniform(0, 10, seed);
if (std > 0) {
test_normal(mean, std, seed);
}
}
printf("Testing larger normals\n");
for (int i = 0; i < 100; i++) {
double mean = sample_uniform(-1000 * 1000, 1000 * 1000, seed);
double std = sample_uniform(0, 1000 * 1000, seed);
if (std > 0) {
test_normal(mean, std, seed);
}
}
2023-07-23 14:28:44 +00:00
printf("Testing smaller lognormals\n");
for (int i = 0; i < 100; i++) {
2023-07-23 13:44:22 +00:00
double mean = sample_uniform(-1, 1, seed);
double std = sample_uniform(0, 1, seed);
if (std > 0) {
test_lognormal(mean, std, seed);
}
}
2023-07-23 14:28:44 +00:00
printf("Testing larger lognormals\n");
for (int i = 0; i < 100; i++) {
2023-07-23 13:44:22 +00:00
double mean = sample_uniform(-1, 5, seed);
double std = sample_uniform(0, 5, seed);
if (std > 0) {
test_lognormal(mean, std, seed);
}
}
2023-07-23 14:28:44 +00:00
printf("Testing lognormals — sample_to(low, high) syntax\n");
for (int i = 0; i < 100; i++) {
double low = sample_uniform(0, 1000 * 1000, seed);
double high = sample_uniform(0, 1000 * 1000, seed);
if (low < high) {
test_to(low, high, seed);
}
}
2023-07-23 19:21:54 +00:00
// Bonus example
test_to(10, 10 * 1000, seed);
2023-07-23 14:28:44 +00:00
2023-07-23 13:44:22 +00:00
printf("Testing beta distribution\n");
for (int i = 0; i < 100; i++) {
double a = sample_uniform(0, 1000, seed);
double b = sample_uniform(0, 1000, seed);
if ((a > 0) && (b > 0)) {
test_beta(a, b, seed);
}
}
printf("Testing larger beta distributions\n");
for (int i = 0; i < 100; i++) {
double a = sample_uniform(0, 1000 * 1000, seed);
double b = sample_uniform(0, 1000 * 1000, seed);
if ((a > 0) && (b > 0)) {
test_beta(a, b, seed);
}
}
free(seed);
}