commit 09755124122f035598e65d97127dbcd231c24974
parent b4c50996cd611eb51bce6999ae29da098205883d
Author: NunoSempere <nuno.sempere@protonmail.com>
Date: Thu, 1 Feb 2024 20:26:37 +0100
remove functionality
- Sample from arbitrary cdf: unused complexity
- Sample confidence interval directly from cdf: makes sampling
function/array function boundary unclear.
Diffstat:
| M | squiggle_more.c | | | 241 | ++++--------------------------------------------------------------------------- |
1 file changed, 11 insertions(+), 230 deletions(-)
diff --git a/squiggle_more.c b/squiggle_more.c
@@ -194,6 +194,17 @@ double array_get_median(double xs[], int n){
return quickselect(median_k, xs, n);
}
+/* array print: potentially useful for debugging */
+void array_print(double xs[], int n)
+{
+ printf("[");
+ for (int i = 0; i < n - 1; i++) {
+ printf("%f, ", xs[i]);
+ }
+ printf("%f", xs[n - 1]);
+ printf("]\n");
+}
+
void array_print_stats(double xs[], int n){
ci ci_90 = array_get_ci((ci) { .low = 0.05, .high = 0.95 }, xs, n);
ci ci_80 = array_get_ci((ci) { .low = 0.1, .high = 0.9 }, xs, n);
@@ -391,23 +402,6 @@ void array_print_90_ci_histogram(double* xs, int n_samples, int n_bins){
}
-// Replicate some of the above functions over samplers
-// However, in the future I'll delete this
-// There should be a clear boundary between working with samplers and working with an array of samples
-ci sampler_get_ci(ci interval, double (*sampler)(uint64_t*), int n, uint64_t* seed)
-{
- UNUSED(seed); // don't want to use it right now, but want to preserve ability to do so (e.g., remove parallelism from internals). Also nicer for consistency.
- double* xs = malloc((size_t)n * sizeof(double));
- sampler_parallel(sampler, xs, 16, n);
- ci result = array_get_ci(interval, xs, n);
- free(xs);
- return result;
-}
-ci sampler_get_90_ci(double (*sampler)(uint64_t*), int n, uint64_t* seed)
-{
- return sampler_get_ci((ci) { .low = 0.05, .high = 0.95 }, sampler, n, seed);
-}
-
/* Algebra manipulations */
#define NORMAL90CONFIDENCE 1.6448536269514727
@@ -458,216 +452,3 @@ ci convert_lognormal_params_to_ci(lognormal_params y)
ci result = { .low = exp(loglow), .high = exp(loghigh) };
return result;
}
-
-/* Scaffolding to handle errors */
-// We will sample from an arbitrary cdf
-// and that operation might fail
-// so we build some scaffolding here
-
-#define MAX_ERROR_LENGTH 500
-#define EXIT_ON_ERROR 0
-#define PROCESS_ERROR(error_msg) process_error(error_msg, EXIT_ON_ERROR, __FILE__, __LINE__)
-
-typedef struct box_t {
- int empty;
- double content;
- char* error_msg;
-} box;
-
-box process_error(const char* error_msg, int should_exit, char* file, int line)
-{
- if (should_exit) {
- printf("%s, @, in %s (%d)", error_msg, file, line);
- exit(1);
- } else {
- char error_msg[MAX_ERROR_LENGTH];
- snprintf(error_msg, MAX_ERROR_LENGTH, "@, in %s (%d)", file, line); // NOLINT: We are being carefull here by considering MAX_ERROR_LENGTH explicitly.
- box error = { .empty = 1, .error_msg = error_msg };
- return error;
- }
-}
-
-/* Invert an arbitrary cdf at a point */
-// Version #1:
-// - input: (cdf: double => double, p)
-// - output: Box(number|error)
-box inverse_cdf_double(double cdf(double), double p)
-{
- // given a cdf: [-Inf, Inf] => [0,1]
- // returns a box with either
- // x such that cdf(x) = p
- // or an error
- // if EXIT_ON_ERROR is set to 1, it exits instead of providing an error
-
- double low = -1.0;
- double high = 1.0;
-
- // 1. Make sure that cdf(low) < p < cdf(high)
- int interval_found = 0;
- while ((!interval_found) && (low > -DBL_MAX / 4) && (high < DBL_MAX / 4)) {
- // for floats, use FLT_MAX instead
- // Note that this approach is overkill
- // but it's also the *correct* thing to do.
-
- int low_condition = (cdf(low) < p);
- int high_condition = (p < cdf(high));
- if (low_condition && high_condition) {
- interval_found = 1;
- } else if (!low_condition) {
- low = low * 2;
- } else if (!high_condition) {
- high = high * 2;
- }
- }
-
- if (!interval_found) {
- return PROCESS_ERROR("Interval containing the target value not found, in function inverse_cdf");
- } else {
-
- int convergence_condition = 0;
- int count = 0;
- while (!convergence_condition && (count < (INT_MAX / 2))) {
- double mid = (high + low) / 2;
- int mid_not_new = (mid == low) || (mid == high);
- // double width = high - low;
- // if ((width < 1e-8) || mid_not_new){
- if (mid_not_new) {
- convergence_condition = 1;
- } else {
- double mid_sign = cdf(mid) - p;
- if (mid_sign < 0) {
- low = mid;
- } else if (mid_sign > 0) {
- high = mid;
- } else if (mid_sign == 0) {
- low = mid;
- high = mid;
- }
- }
- }
-
- if (convergence_condition) {
- box result = { .empty = 0, .content = low };
- return result;
- } else {
- return PROCESS_ERROR("Search process did not converge, in function inverse_cdf");
- }
- }
-}
-
-// Version #2:
-// - input: (cdf: double => Box(number|error), p)
-// - output: Box(number|error)
-box inverse_cdf_box(box cdf_box(double), double p)
-{
- // given a cdf: [-Inf, Inf] => Box([0,1])
- // returns a box with either
- // x such that cdf(x) = p
- // or an error
- // if EXIT_ON_ERROR is set to 1, it exits instead of providing an error
-
- double low = -1.0;
- double high = 1.0;
-
- // 1. Make sure that cdf(low) < p < cdf(high)
- int interval_found = 0;
- while ((!interval_found) && (low > -DBL_MAX / 4) && (high < DBL_MAX / 4)) {
- // for floats, use FLT_MAX instead
- // Note that this approach is overkill
- // but it's also the *correct* thing to do.
- box cdf_low = cdf_box(low);
- if (cdf_low.empty) {
- return PROCESS_ERROR(cdf_low.error_msg);
- }
-
- box cdf_high = cdf_box(high);
- if (cdf_high.empty) {
- return PROCESS_ERROR(cdf_low.error_msg);
- }
-
- int low_condition = (cdf_low.content < p);
- int high_condition = (p < cdf_high.content);
- if (low_condition && high_condition) {
- interval_found = 1;
- } else if (!low_condition) {
- low = low * 2;
- } else if (!high_condition) {
- high = high * 2;
- }
- }
-
- if (!interval_found) {
- return PROCESS_ERROR("Interval containing the target value not found, in function inverse_cdf");
- } else {
-
- int convergence_condition = 0;
- int count = 0;
- while (!convergence_condition && (count < (INT_MAX / 2))) {
- double mid = (high + low) / 2;
- int mid_not_new = (mid == low) || (mid == high);
- // double width = high - low;
- if (mid_not_new) {
- // if ((width < 1e-8) || mid_not_new){
- convergence_condition = 1;
- } else {
- box cdf_mid = cdf_box(mid);
- if (cdf_mid.empty) {
- return PROCESS_ERROR(cdf_mid.error_msg);
- }
- double mid_sign = cdf_mid.content - p;
- if (mid_sign < 0) {
- low = mid;
- } else if (mid_sign > 0) {
- high = mid;
- } else if (mid_sign == 0) {
- low = mid;
- high = mid;
- }
- }
- }
-
- if (convergence_condition) {
- box result = { .empty = 0, .content = low };
- return result;
- } else {
- return PROCESS_ERROR("Search process did not converge, in function inverse_cdf");
- }
- }
-}
-
-/* Sample from an arbitrary cdf */
-// Before: invert an arbitrary cdf at a point
-// Now: from an arbitrary cdf, get a sample
-box sampler_cdf_box(box cdf(double), uint64_t* seed)
-{
- double p = sample_unit_uniform(seed);
- box result = inverse_cdf_box(cdf, p);
- return result;
-}
-box sampler_cdf_double(double cdf(double), uint64_t* seed)
-{
- double p = sample_unit_uniform(seed);
- box result = inverse_cdf_double(cdf, p);
- return result;
-}
-double sampler_cdf_danger(box cdf(double), uint64_t* seed)
-{
- double p = sample_unit_uniform(seed);
- box result = inverse_cdf_box(cdf, p);
- if (result.empty) {
- exit(1);
- } else {
- return result.content;
- }
-}
-
-/* array print: potentially useful for debugging */
-void array_print(double xs[], int n)
-{
- printf("[");
- for (int i = 0; i < n - 1; i++) {
- printf("%f, ", xs[i]);
- }
- printf("%f", xs[n - 1]);
- printf("]\n");
-}