forked from personal/squiggle.c
simplify PROCESS_ERROR macro
This commit is contained in:
parent
11e965be4f
commit
6247fbfb7b
13
README.md
13
README.md
|
@ -12,7 +12,7 @@ A self-contained C99 library that provides a subset of [Squiggle](https://www.sq
|
||||||
- Because if you can implement something in C, you can implement it anywhere else
|
- Because if you can implement something in C, you can implement it anywhere else
|
||||||
- Because it can be made faster if need be, e.g., with a multi-threading library like OpenMP, or by adding more algorithmic complexity
|
- Because it can be made faster if need be, e.g., with a multi-threading library like OpenMP, or by adding more algorithmic complexity
|
||||||
|
|
||||||
## The core scheme
|
## The core strategy
|
||||||
|
|
||||||
Have some basic building blocks, like , and return samplers. Use previous samplers to . Then use the final sampler to produce an array of samples.
|
Have some basic building blocks, like , and return samplers. Use previous samplers to . Then use the final sampler to produce an array of samples.
|
||||||
|
|
||||||
|
@ -26,6 +26,13 @@ You can follow some example usage in the examples/ folder
|
||||||
4. In the fourth example, we define some simple cdfs, and we draw samples from those cdfs. We see that this approach is slower than using the built-in samplers, e.g., the normal sampler.
|
4. In the fourth example, we define some simple cdfs, and we draw samples from those cdfs. We see that this approach is slower than using the built-in samplers, e.g., the normal sampler.
|
||||||
5. In the fifth example, we define the cdf for the beta distribution, and we draw samples from it.
|
5. In the fifth example, we define the cdf for the beta distribution, and we draw samples from it.
|
||||||
|
|
||||||
|
## Related projects
|
||||||
|
|
||||||
|
- [Squiggle](https://www.squiggle-language.com/)
|
||||||
|
- [SquigglePy](https://github.com/rethinkpriorities/squigglepy)
|
||||||
|
- [time to botec](https://github.com/NunoSempere/time-to-botec)
|
||||||
|
- [simple squiggle](https://nunosempere.com/blog/2022/04/17/simple-squiggle/)
|
||||||
|
|
||||||
## To do list
|
## To do list
|
||||||
|
|
||||||
- [ ] Have some more complicated & realistic example
|
- [ ] Have some more complicated & realistic example
|
||||||
|
@ -34,9 +41,11 @@ You can follow some example usage in the examples/ folder
|
||||||
- Schema: a function which takes a sample and manipulates it,
|
- Schema: a function which takes a sample and manipulates it,
|
||||||
- and at the end, an array of samples.
|
- and at the end, an array of samples.
|
||||||
- Explain boxes
|
- Explain boxes
|
||||||
- Explain individual examples
|
- [x] Explain individual examples
|
||||||
- Explain nested functions
|
- Explain nested functions
|
||||||
- [ ] Publish online
|
- [ ] Publish online
|
||||||
|
- [ ] Support all distribution functions in <https://www.squiggle-language.com/docs/Api/Dist>
|
||||||
|
- [ ] Support all distribution functions in <https://www.squiggle-language.com/docs/Api/Dist>, and do so efficiently
|
||||||
|
|
||||||
## Done
|
## Done
|
||||||
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -42,7 +42,7 @@ struct box incbeta(float a, float b, float x)
|
||||||
* 3. This notice may not be removed or altered from any source distribution.
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
*/
|
*/
|
||||||
if (x < 0.0 || x > 1.0) {
|
if (x < 0.0 || x > 1.0) {
|
||||||
PROCESS_ERROR("x out of bounds [0, 1], in function incbeta");
|
return PROCESS_ERROR("x out of bounds [0, 1], in function incbeta");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*The continued fraction converges nicely for x < (a+1)/(a+b+2)*/
|
/*The continued fraction converges nicely for x < (a+1)/(a+b+2)*/
|
||||||
|
@ -102,7 +102,7 @@ struct box incbeta(float a, float b, float x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PROCESS_ERROR("More loops needed, did not converge, in function incbeta");
|
return PROCESS_ERROR("More loops needed, did not converge, in function incbeta");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct box cdf_beta(float x)
|
struct box cdf_beta(float x)
|
||||||
|
|
45
squiggle.c
45
squiggle.c
|
@ -6,20 +6,9 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#define EXIT_ON_ERROR 0
|
|
||||||
#define MAX_ERROR_LENGTH 500
|
#define MAX_ERROR_LENGTH 500
|
||||||
#define PROCESS_ERROR(...) \
|
#define EXIT_ON_ERROR 0
|
||||||
do { \
|
#define PROCESS_ERROR(error_msg) process_error(error_msg, EXIT_ON_ERROR, __FILE__, __LINE__)
|
||||||
if (EXIT_ON_ERROR) { \
|
|
||||||
printf("@, in %s (%d)", __FILE__, __LINE__); \
|
|
||||||
exit(1); \
|
|
||||||
} else { \
|
|
||||||
char error_msg[MAX_ERROR_LENGTH]; \
|
|
||||||
snprintf(error_msg, MAX_ERROR_LENGTH, "@, in %s (%d)", __FILE__, __LINE__); \
|
|
||||||
struct box error = { .empty = 1, .error_msg = error_msg }; \
|
|
||||||
return error; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
// PI constant
|
// PI constant
|
||||||
const float PI = 3.14159265358979323846; // M_PI in gcc gnu99
|
const float PI = 3.14159265358979323846; // M_PI in gcc gnu99
|
||||||
|
@ -139,6 +128,18 @@ struct box {
|
||||||
char* error_msg;
|
char* error_msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct box process_error(const char* error_msg, int should_exit, char* file, int line){
|
||||||
|
if(should_exit){
|
||||||
|
printf("@, in %s (%d)", file, line);
|
||||||
|
exit(1);
|
||||||
|
}else{
|
||||||
|
char error_msg[MAX_ERROR_LENGTH];
|
||||||
|
snprintf(error_msg, MAX_ERROR_LENGTH, "@, in %s (%d)", file, line);
|
||||||
|
struct box error = { .empty = 1, .error_msg = error_msg };
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Inverse cdf at point
|
// Inverse cdf at point
|
||||||
// Two versions of this function:
|
// Two versions of this function:
|
||||||
// - raw, dealing with cdfs that return floats
|
// - raw, dealing with cdfs that return floats
|
||||||
|
@ -176,7 +177,7 @@ struct box inverse_cdf_float(float cdf(float), float p)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!interval_found) {
|
if (!interval_found) {
|
||||||
PROCESS_ERROR("Interval containing the target value not found, in function inverse_cdf");
|
return PROCESS_ERROR("Interval containing the target value not found, in function inverse_cdf");
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
int convergence_condition = 0;
|
int convergence_condition = 0;
|
||||||
|
@ -205,7 +206,7 @@ struct box inverse_cdf_float(float cdf(float), float p)
|
||||||
struct box result = { .empty = 0, .content = low };
|
struct box result = { .empty = 0, .content = low };
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
PROCESS_ERROR("Search process did not converge, in function inverse_cdf");
|
return PROCESS_ERROR("Search process did not converge, in function inverse_cdf");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,12 +229,12 @@ struct box inverse_cdf_box(struct box cdf_box(float), float p)
|
||||||
// but it's also the *correct* thing to do.
|
// but it's also the *correct* thing to do.
|
||||||
struct box cdf_low = cdf_box(low);
|
struct box cdf_low = cdf_box(low);
|
||||||
if (cdf_low.empty) {
|
if (cdf_low.empty) {
|
||||||
PROCESS_ERROR(cdf_low.error_msg);
|
return PROCESS_ERROR(cdf_low.error_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct box cdf_high = cdf_box(high);
|
struct box cdf_high = cdf_box(high);
|
||||||
if (cdf_high.empty) {
|
if (cdf_high.empty) {
|
||||||
PROCESS_ERROR(cdf_low.error_msg);
|
return PROCESS_ERROR(cdf_low.error_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int low_condition = (cdf_low.content < p);
|
int low_condition = (cdf_low.content < p);
|
||||||
|
@ -248,7 +249,7 @@ struct box inverse_cdf_box(struct box cdf_box(float), float p)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!interval_found) {
|
if (!interval_found) {
|
||||||
PROCESS_ERROR("Interval containing the target value not found, in function inverse_cdf");
|
return PROCESS_ERROR("Interval containing the target value not found, in function inverse_cdf");
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
int convergence_condition = 0;
|
int convergence_condition = 0;
|
||||||
|
@ -263,7 +264,7 @@ struct box inverse_cdf_box(struct box cdf_box(float), float p)
|
||||||
} else {
|
} else {
|
||||||
struct box cdf_mid = cdf_box(mid);
|
struct box cdf_mid = cdf_box(mid);
|
||||||
if (cdf_mid.empty) {
|
if (cdf_mid.empty) {
|
||||||
PROCESS_ERROR(cdf_mid.error_msg);
|
return PROCESS_ERROR(cdf_mid.error_msg);
|
||||||
}
|
}
|
||||||
float mid_sign = cdf_mid.content - p;
|
float mid_sign = cdf_mid.content - p;
|
||||||
if (mid_sign < 0) {
|
if (mid_sign < 0) {
|
||||||
|
@ -281,19 +282,19 @@ struct box inverse_cdf_box(struct box cdf_box(float), float p)
|
||||||
struct box result = { .empty = 0, .content = low };
|
struct box result = { .empty = 0, .content = low };
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
PROCESS_ERROR("Search process did not converge, in function inverse_cdf");
|
return PROCESS_ERROR("Search process did not converge, in function inverse_cdf");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sampler based on inverse cdf and randomness function
|
// Sampler based on inverse cdf and randomness function
|
||||||
struct box sampler_box_cdf(struct box cdf(float), uint32_t* seed)
|
struct box sampler_cdf_box(struct box cdf(float), uint32_t* seed)
|
||||||
{
|
{
|
||||||
float p = rand_0_to_1(seed);
|
float p = rand_0_to_1(seed);
|
||||||
struct box result = inverse_cdf_box(cdf, p);
|
struct box result = inverse_cdf_box(cdf, p);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
struct box sampler_float_cdf(float cdf(float), uint32_t* seed)
|
struct box sampler_cdf_float(float cdf(float), uint32_t* seed)
|
||||||
{
|
{
|
||||||
float p = rand_0_to_1(seed);
|
float p = rand_0_to_1(seed);
|
||||||
struct box result = inverse_cdf_float(cdf, p);
|
struct box result = inverse_cdf_float(cdf, p);
|
||||||
|
|
16
squiggle.h
16
squiggle.h
|
@ -33,20 +33,10 @@ struct box {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Macros to handle errors
|
// Macros to handle errors
|
||||||
#define EXIT_ON_ERROR 0
|
|
||||||
#define MAX_ERROR_LENGTH 500
|
#define MAX_ERROR_LENGTH 500
|
||||||
#define PROCESS_ERROR(...) \
|
#define EXIT_ON_ERROR 0
|
||||||
do { \
|
#define PROCESS_ERROR(error_msg) process_error(error_msg, EXIT_ON_ERROR, __FILE__, __LINE__)
|
||||||
if (EXIT_ON_ERROR) { \
|
struct box process_error(const char* error_msg, int should_exit, char* file, int line);
|
||||||
printf("@, in %s (%d)", __FILE__, __LINE__); \
|
|
||||||
exit(1); \
|
|
||||||
} else { \
|
|
||||||
char error_msg[MAX_ERROR_LENGTH]; \
|
|
||||||
snprintf(error_msg, MAX_ERROR_LENGTH, "@, in %s (%d)", __FILE__, __LINE__); \
|
|
||||||
struct box error = { .empty = 1, .error_msg = error_msg }; \
|
|
||||||
return error; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
// Inverse cdf
|
// Inverse cdf
|
||||||
struct box inverse_cdf_float(float cdf(float), float p);
|
struct box inverse_cdf_float(float cdf(float), float p);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user