/* Probabilistic programming in C The famous sprinkle example: given that the grass is wet on a given day, did it rain or did the sprinkler come on? This code is the C realization of the following OCaml code (which uses our library for probabilistic programming in OCaml): let grass_model () = let rain = flip 0.3 and sprinkler = flip 0.5 in let grass_is_wet = (flip 0.9 && rain) || (flip 0.8 && sprinkler) || flip 0.1 in if not grass_is_wet then fail (); rain;; let [(0.2838, V true); (0.322, V false)] = reify None grass_model;; (* 14 worlds are examined *) As we see below, the C code looks almost the same, modulo a few syntactic differences between C and OCaml. The idea for this code has been suggested by Chung-chieh Shan. In our C code, we use fork(2) to emulate probabilistic choice. To be precise, we use fork(2) for non-deterministic choice, and keep track of the weight separately, in a per-process variable Weight. This program writes on the standard output the results of all choices. Each line has two space-separated fields. The first field is the probability, the second field is the outcome, a letter T or F. The output is intended to be processed by a program like AWK, as shown below. In the spirit of UNIX, each program ought to do one thing: generate results or post-process them (truthfully though, we separate out post-processing to avoid doing it in C and to avoid obscuring the communication pattern). Compile and invoke this program as follows: gcc -o grass grass.c ./grass | awk '{r[$2] += $1}; END {printf "T: %g; F: %g",r["T"],r["F"]}' The produced output: T: 0.2838; F: 0.322 */ #include #include #include #include #include #define bool int #define true 1 #define false 0 /* prototypes */ bool flip(const double); void fail(void) { abort(); } bool grass_model (void) { /* compare with the OCaml code above */ bool rain = flip(0.3); bool sprinkler = flip(0.5); bool grass_is_wet = (flip(0.9) && rain) || (flip(0.8) && sprinkler) || flip(0.1); if( !grass_is_wet ) fail(); return rain; } /* --------------------------------------------------------------------- The implementation of the framework */ static double MyWeight = 1.0; /* changed at the start-up of each process */ bool flip(const double p) { pid_t pid = fork(); if(pid == 0) { /* in the child process, to handle False */ MyWeight *= 1.0 - p; return false; } else if(pid == (pid_t)(-1)) { perror("fork failed"); abort(); } else { /* in the parent process, to handle True */ MyWeight *= p; return true; } } void runit(void) { /* Run the model */ bool result = grass_model(); printf("%g %c\n",MyWeight,result ? 'T' : 'F'); } /* The main function */ int main(void) { int status; runit(); while (wait(&status) > 0) ; return 0; }