squiggle.c

Self-contained Monte Carlo estimation in C99
Log | Files | Refs | README

commit d744bcd354811876058f9a3b69fedbb3ba54df10
parent 9578461494032c0a9aadf7e01af19cb9e1710f63
Author: NunoSempere <nuno.sempere@protonmail.com>
Date:   Sat, 15 Jul 2023 23:22:44 +0200

savepoint

Diffstat:
Mexamples/01_one_sample/example | 0
Mexamples/02_many_samples/example | 0
Aexamples/03_gcc_nested_function/example | 0
Aexamples/03_gcc_nested_function/example.c | 37+++++++++++++++++++++++++++++++++++++
Aexamples/03_gcc_nested_function/makefile | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msquiggle.h | 5++++-
Mto-do.md | 5+++--
7 files changed, 101 insertions(+), 3 deletions(-)

diff --git a/examples/01_one_sample/example b/examples/01_one_sample/example Binary files differ. diff --git a/examples/02_many_samples/example b/examples/02_many_samples/example Binary files differ. diff --git a/examples/03_gcc_nested_function/example b/examples/03_gcc_nested_function/example Binary files differ. diff --git a/examples/03_gcc_nested_function/example.c b/examples/03_gcc_nested_function/example.c @@ -0,0 +1,37 @@ +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include "../../squiggle.h" + +int main(){ + // set randomness seed + uint32_t* seed = malloc(sizeof(uint32_t)); + *seed = 1000; // xorshift can't start with 0 + + float p_a = 0.8; + float p_b = 0.5; + float p_c = p_a * p_b; + + int n_dists = 4; + + float sample_0(uint32_t* seed){ return 0; } + float sample_1(uint32_t* seed) { return 1; } + float sample_few(uint32_t* seed){ return random_to(1, 3, seed); } + float sample_many(uint32_t* seed){ return random_to(2, 10, seed); } + + float (*samplers[])(uint32_t*) = { sample_0, sample_1, sample_few, sample_many }; + float weights[] = { 1 - p_c, p_c / 2, p_c / 4, p_c / 4 }; + + int n_samples = 1000000; + float* result_many = (float *) malloc(n_samples * sizeof(float)); + for(int i=0; i<n_samples; i++){ + result_many[i] = mixture(samplers, weights, n_dists, seed); + } + + printf("result_many: ["); + for(int i=0; i<100; i++){ + printf("%.2f, ", result_many[i]); + } + printf("]\n"); +} + diff --git a/examples/03_gcc_nested_function/makefile b/examples/03_gcc_nested_function/makefile @@ -0,0 +1,57 @@ +# Interface: +# make +# make build +# make format +# make run + +# Compiler +CC=gcc # required for nested functions +# CC=tcc # <= faster compilation + +# Main file +SRC=example.c +OUTPUT=example + +## Dependencies +MATH=-lm +DEPENDENCIES=$(MATH) +# OPENMP=-fopenmp + +## Flags +DEBUG= #'-g' +STANDARD=-std=gnu99 ## allows for nested functions. +EXTENSIONS= #-fnested-functions +WARNINGS=-Wall +OPTIMIZED=-O3#-Ofast +CFLAGS=$(DEBUG) $(STANDARD) $(EXTENSIONS) $(WARNINGS) $(OPTIMIZED) + +## Formatter +STYLE_BLUEPRINT=webkit +FORMATTER=clang-format -i -style=$(STYLE_BLUEPRINT) + +## make build +build: $(SRC) + # gcc -std=gnu99 example.c -lm -o example + $(CC) $(CFLAGS) $(SRC) $(DEPENDENCIES) -o $(OUTPUT) + +format: $(SRC) + $(FORMATTER) $(SRC) + +run: $(SRC) $(OUTPUT) + ./$(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/squiggle.h b/squiggle.h @@ -95,14 +95,17 @@ float mixture(float (*samplers[])(uint32_t*), float* weights, int n_dists, uint3 cumsummed_normalized_weights[i] = cumsummed_normalized_weights[i - 1] + weights[i]/sum_weights; } - float p = random_uniform(0, 1, seed); float result; + int result_set_flag = 0; + float p = random_uniform(0, 1, seed); for (int k = 0; k < n_dists; k++) { if (p < cumsummed_normalized_weights[k]) { result = samplers[k](seed); + result_set_flag = 1; break; } } + if(result_set_flag == 0) result = samplers[n_dists-1](seed); free(cumsummed_normalized_weights); return result; diff --git a/to-do.md b/to-do.md @@ -1,9 +1,10 @@ -- [ ] Add example for only one sample -- [ ] Add example for many samples +- [x] Add example for only one sample +- [x] Add example for many samples - [ ] Use gcc extension to define functions nested inside main. - [ ] Use OpenMP for acceleration - [ ] Chain various mixture functions - [ ] Have some more complicated & realistic example - [ ] Add summarization functions, like mean, std, 90% ci (or all c.i.?) - [ ] Add beta distribution +- [ ] Add a custom preprocessor to allow simple nested functions that don't rely on local scope?