diff --git a/README.md b/README.md index 2d77667..5fc3c87 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Squiggle.c -A self-contained C99 library that provides a subset of [Squiggle](https://www.squiggle-language.com/)'s functionality in C. It should be fast, but at the margin, simplicity of implementation wins over speed. +A self-contained C99 library that provides a subset of [Squiggle](https://www.squiggle-language.com/)'s functionality in C. ## Why C? @@ -70,6 +70,82 @@ The first approach produces terser programs but might not scale. The second appr Behaviour on error can be toggled by the `EXIT_ON_ERROR` variable. This library also provides a convenient macro, `PROCESS_ERROR`, to make error handling in either case much terser—see the usage in example 4 in the examples/ folder. +## Design choices + +This code should aim to be fast, but at the margin, simplicity of implementation wins over speed. For example, there are various possible algorithms to sample a distribution, one of which is faster in part of the domain, I'm choosing to only have one algorithm and pay the—normally small—performance penalty. + +## Correlated samples + +In the parent [squiggle](https://www.squiggle-language.com/) language, there is some ambiguity about what this code means: + +``` +a = 1 to 10 +b = 2 * a +c = b/a +c +``` + +Should `c` be equal to `2`? or should it be equal to 2 times the expected ratio of two independent draws from a (`2 * a/a`, as it were)? + +In squiggle.c, this ambiguity doesn't exist, at the cost of greater verbosity: + +```c +// correlated samples +// gcc -O3 correlated.c squiggle.c -lm -o correlated + +#include "squiggle.h" +#include +#include +#include + +int main(){ + // set randomness seed + uint32_t* seed = malloc(sizeof(uint32_t)); + *seed = 1000; // xorshift can't start with a seed of 0 + + float a = sample_to(1, 10, seed); + float b = 2 * a; + float c = b / a; + + printf("a: %f, b: %f, c: %f\n", a, b, c); + // a: 0.607162, b: 1.214325, c: 0.500000 + + free(seed); +} +``` + +vs + +```c +// uncorrelated samples +// gcc -O3 uncorrelated.c ../../squiggle.c -lm -o uncorrelated + +#include "squiggle.h" +#include +#include +#include + +float draw_xyz(uint32_t* seed){ + // function could also be placed inside main with gcc nested functions extension. + return sample_to(1, 20, seed); +} + +int main(){ + // set randomness seed + uint32_t* seed = malloc(sizeof(uint32_t)); + *seed = 1000; // xorshift can't start with a seed of 0 + + float a = draw_xyz(seed); + float b = 2 * draw_xyz(seed); + float c = b / a; + + printf("a: %f, b: %f, c: %f\n", a, b, c); + // a: 0.522484, b: 10.283501, c: 19.681936 + + free(seed) +} +``` + ## Related projects - [Squiggle](https://www.squiggle-language.com/) diff --git a/scratchpad/correlated/correlated b/scratchpad/correlated/correlated new file mode 100755 index 0000000..533ab80 Binary files /dev/null and b/scratchpad/correlated/correlated differ diff --git a/scratchpad/correlated/correlated.c b/scratchpad/correlated/correlated.c new file mode 100644 index 0000000..cd53eae --- /dev/null +++ b/scratchpad/correlated/correlated.c @@ -0,0 +1,21 @@ +// correlated samples + +#include "../../squiggle.h" +#include +#include +#include + +int main() +{ + // set randomness seed + uint32_t* seed = malloc(sizeof(uint32_t)); + *seed = 1000; // xorshift can't start with 0 + + float a = sample_to(1, 10, seed); + float b = 2 * a; + float c = a / b; + + printf("a: %f, b: %f, c: %f\n", a, b, c); + + free(seed); +} diff --git a/scratchpad/correlated/makefile b/scratchpad/correlated/makefile new file mode 100644 index 0000000..90a3e63 --- /dev/null +++ b/scratchpad/correlated/makefile @@ -0,0 +1,53 @@ +# Interface: +# make +# make build +# make format +# make run + +# Compiler +CC=gcc +# CC=tcc # <= faster compilation + +# Main file +SRC=correlated.c ../../squiggle.c +OUTPUT=correlated + +## Dependencies +MATH=-lm + +## Flags +DEBUG= #'-g' +STANDARD=-std=c99 +WARNINGS=-Wall +OPTIMIZED=-O3 #-Ofast +# OPENMP=-fopenmp + +## Formatter +STYLE_BLUEPRINT=webkit +FORMATTER=clang-format -i -style=$(STYLE_BLUEPRINT) + +## make build +build: $(SRC) + $(CC) $(OPTIMIZED) $(DEBUG) $(SRC) $(MATH) -o $(OUTPUT) + +format: $(SRC) + $(FORMATTER) $(SRC) + +run: $(SRC) $(OUTPUT) + OMP_NUM_THREADS=1 ./$(OUTPUT) && echo + +time-linux: + @echo "Requires /bin/time, found on GNU/Linux systems" && echo + + @echo "Running 100x and taking avg time $(OUTPUT)" + @t=$$(/usr/bin/time -f "%e" -p bash -c 'for i in {1..100}; do $(OUTPUT); done' 2>&1 >/dev/null | grep real | awk '{print $$2}' ); echo "scale=2; 1000 * $$t / 100" | bc | sed "s|^|Time using 1 thread: |" | sed 's|$$|ms|' && echo + +## Profiling + +profile-linux: + echo "Requires perf, which depends on the kernel version, and might be in linux-tools package or similar" + echo "Must be run as sudo" + $(CC) $(SRC) $(MATH) -o $(OUTPUT) + sudo perf record ./$(OUTPUT) + sudo perf report + rm perf.data diff --git a/scratchpad/uncorrelated/makefile b/scratchpad/uncorrelated/makefile new file mode 100644 index 0000000..bf9f32d --- /dev/null +++ b/scratchpad/uncorrelated/makefile @@ -0,0 +1,53 @@ +# Interface: +# make +# make build +# make format +# make run + +# Compiler +CC=gcc +# CC=tcc # <= faster compilation + +# Main file +SRC=uncorrelated.c ../../squiggle.c +OUTPUT=uncorrelated + +## Dependencies +MATH=-lm + +## Flags +DEBUG= #'-g' +STANDARD=-std=c99 +WARNINGS=-Wall +OPTIMIZED=-O3 #-Ofast +# OPENMP=-fopenmp + +## Formatter +STYLE_BLUEPRINT=webkit +FORMATTER=clang-format -i -style=$(STYLE_BLUEPRINT) + +## make build +build: $(SRC) + $(CC) $(OPTIMIZED) $(DEBUG) $(SRC) $(MATH) -o $(OUTPUT) + +format: $(SRC) + $(FORMATTER) $(SRC) + +run: $(SRC) $(OUTPUT) + OMP_NUM_THREADS=1 ./$(OUTPUT) && echo + +time-linux: + @echo "Requires /bin/time, found on GNU/Linux systems" && echo + + @echo "Running 100x and taking avg time $(OUTPUT)" + @t=$$(/usr/bin/time -f "%e" -p bash -c 'for i in {1..100}; do $(OUTPUT); done' 2>&1 >/dev/null | grep real | awk '{print $$2}' ); echo "scale=2; 1000 * $$t / 100" | bc | sed "s|^|Time using 1 thread: |" | sed 's|$$|ms|' && echo + +## Profiling + +profile-linux: + echo "Requires perf, which depends on the kernel version, and might be in linux-tools package or similar" + echo "Must be run as sudo" + $(CC) $(SRC) $(MATH) -o $(OUTPUT) + sudo perf record ./$(OUTPUT) + sudo perf report + rm perf.data diff --git a/scratchpad/uncorrelated/uncorrelated b/scratchpad/uncorrelated/uncorrelated new file mode 100755 index 0000000..2ba1a2c Binary files /dev/null and b/scratchpad/uncorrelated/uncorrelated differ diff --git a/scratchpad/uncorrelated/uncorrelated.c b/scratchpad/uncorrelated/uncorrelated.c new file mode 100644 index 0000000..4fbe05d --- /dev/null +++ b/scratchpad/uncorrelated/uncorrelated.c @@ -0,0 +1,24 @@ +// uncorrelated samples + +#include "../../squiggle.h" +#include +#include +#include + +float draw_xyz(uint32_t* seed){ + // function could also be placed inside main with gcc nested functions extension. + return sample_to(1, 20, seed); +} + +int main(){ + // set randomness seed + uint32_t* seed = malloc(sizeof(uint32_t)); + *seed = 1000; // xorshift can't start with 0 + + float a = draw_xyz(seed); + float b = 2 * draw_xyz(seed); + float c = b / a; + + printf("a: %f, b: %f, c: %f\n", a, b, c); + +}