(*
Airplane-blip example from the BLOG papers of Brian Milch et al.
This example was mentioned in Stuart Russell's talk at the
NIPS2008 Probabilistic Programming workshop.
This example is meant to show-case open worlds and BLOG's ability
to reason with open worlds.
The blip example is HMM with a twist: the number of airplanes is not
fixed; rather, it is described by a geometric distribution. Any number
of airplanes is possible (although with progreessively decreasing
probabilities).
The current code is based on the AILog implementation of the blip example,
available on the AILog2 web page.
To run the example:
pl -s ../ailog/ailog2.pl
ailog: load 'blip.cil'.
ailog: observe blip(3,3,0) & blip(3,4,next(0)).
Answer: P(blip(3, 3, 0) & blip(3, 4, next(0))|Obs)=[0.000544527, 0.00571287].
Runtime since last report: 0.0 secs.
[ok,more,explanations,worlds,help]: worlds.
0: [~blipRandomlyOccurs(3, 3, 0), ~more(aircraft, 1, 0.15), producesBlip(1, 0), producesBlip(1, next(0)), direction(1, 0, north), more(aircraft, 0, 0.15), xpos(1, 0, 3), ypos(1, 0, 3), xDer(1, 0, north, 0), yDer(1, 0, north, 1)] Prob=0.000141693
1: [~more(aircraft, 1, 0.15), blipRandomlyOccurs(3, 3, 0), blipRandomlyOccurs(3, 4, next(0))] Prob=0.00034
2: [blipRandomlyOccurs(3, 3, 0), blipRandomlyOccurs(3, 4, next(0)), more(aircraft, 1, 0.15)] Prob=6e-05
3: [~blipRandomlyOccurs(3, 4, next(0)), ~more(aircraft, 1, 0.15), producesBlip(1, 0), producesBlip(1, next(0)), blipRandomlyOccurs(3, 3, 0), direction(1, 0, north), more(aircraft, 0, 0.15), xpos(1, 0, 3), ypos(1, 0, 3), xDer(1, 0, north, 0), yDer(1, 0, north, 1)] Prob=2.83387e-06
Answer: P(blip(3, 3, 0) & blip(3, 4, next(0))|Obs)=[0.000544527, 0.00571287].
Runtime since last report: 0.0 secs.
[ok,more,explanations,worlds,help]: ok.
ailog: load 'blip.cil'.
ailog: observe blip(3,3,0) & blip(3,4,next(0)) & blip(7,8,next(0)) & blip(3,5,next(next(0))).
No (more) answers.
[This means that AILog is unable to compute the answer given its self-imposed
restrictions on the search space. I think AILog probably restricts the
search depth.]
ailog: load 'blip.cil'.
ailog: observe blip(3,3,0) & blip(7,8,next(0)) & blip(3,5,next(next(0))).
No (more) answers.
ailog: observe blip(7,8,next(0)) & blip(3,5,next(next(0))).
Answer: P(blip(7, 8, next(0)) & blip(3, 5, next(next(0)))|Obs)=[0.0004, 0.0334648].
Runtime since last report: 0.03125 secs.
*)
open Ptypes
open ProbM
type dir = North | East | South | West;;
(* --------------- Priors *)
let number_aircrafts () = geometric 0.85;;
let npos = 10;; (* all coordinates are within 0..npos-1 *)
(* Initial (x,y) positions of the plane i *)
let xpos0 i = uniformly [|0;1;2;3;4;5;6;7;8;9|];;
let ypos0 i = uniformly [|0;1;2;3;4;5;6;7;8;9|];;
(* Initial direction of the plane i *)
let dir0 i = uniformly [|North; East; South; West|];;
(* x- or y-Derivatives for the plane i at time t travelling in the direction
dir
*)
let xderiv i t = function
| North -> dist [(0.1, -1); (0.8, 0); (0.1, 1)]
| East -> dist [(0.2, 0); (0.7, 1); (0.1, 2)]
| South -> dist [(0.1, -1); (0.8, 0); (0.1, 1)]
| West -> dist [(0.2, 0); (0.7, -1); (0.1, 2)]
;;
let yderiv i t = function
| North -> dist [(0.2, 0); (0.7, 1); (0.1, 2)]
| East -> dist [(0.1, -1); (0.8, 0); (0.1, 1)]
| South -> dist [(0.2, 0); (0.7, -1); (0.1, 2)]
| West -> dist [(0.1, -1); (0.8, 0); (0.1, 1)]
;;
(* The new direction for the plane i travelling in the direction dir
at the time t
*)
let new_dir i t = function
| North -> dist [(0.2, West); (0.6, North); (0.2, East)]
| East -> dist [(0.2, North); (0.6, East); (0.2, South)]
| South -> dist [(0.2, East); (0.6, South); (0.2, West)]
| West -> dist [(0.2, South); (0.6, West); (0.2, North)]
;;
type pos = int * int;;
(* --------------- The equations of motion and radar detection *)
(* In this first attempt, we have to use memoization. Indeed,
if we know that plane 1 was observed at certain position at time t,
that fact remains no matter how many times we refer to it.
Currently, the expression involing memo has to be executed only when
inference is in progress. That is, we can't define memoized top-level
functions just like
let xpos0 = memo ( ... )
Generally speaking, this restriction is artificial and can be lifted.
After all, executing memo per se does not involve any delimited control.
For now, to avoid thunking of all functions, we use a functor.
*)
(* Memoizing fixpoint combinator *)
let fixm f =
let self = ref (fun v -> failwith "blackhole") in
let g = memo (fun v -> f !self v) in
self := g; g
;;
let rec one_of f = function 0 -> false
| n -> f n || one_of f (pred n)
;;
module BLIPMODEL(S:sig end) = struct
let xpos0 = memo xpos0 (* memoize the priors *)
let ypos0 = memo ypos0
let dir0 = memo dir0
let new_dir = memo (fun (i,t,dir) -> new_dir i t dir)
let xderiv = memo (fun (i,t,dir) -> xderiv i t dir)
let yderiv = memo (fun (i,t,dir) -> yderiv i t dir)
(* Direction of the plane i at time t *)
let direction =
let loop self = function (i,0) -> dir0 i
| (i,t) -> new_dir (i, pred t, self (i,pred t))
in fixm loop
(* Position of the plane i at time t *)
let pos : int * int -> pos =
let loop self = function
| (i,0) -> (xpos0 i, ypos0 i)
| (i,t1) ->
let t = pred t1 in
let (x,y) = self (i,t) in
let dir = direction (i,t) in
let x' = xderiv (i,t,dir) in
let y' = yderiv (i,t,dir) in
let newx = x + x' in
let () = if newx < 0 || newx > 9 then fail () in
let newy = y + y' in
let () = if newy < 0 || newy > 9 then fail () in
(newx,newy)
in fixm loop
(* The radar model from the AILog example code. It is like noisy OR *)
(* anyblip pos t is true if there is a blip at the position p at time t *)
let blip_from i p t = (* blip from plane #i *)
let p' = pos (i,t) in
p = p' && flip 0.9 (* Don't memoize the flip *)
let anyblip1 = memo(
fun (p,t) ->
flip 0.02 || (* randomly occurring blip *)
let nplanes = 1 in
one_of (fun i -> blip_from i p t) nplanes)
let anyblip =
let nplanes = letlazy number_aircrafts in
memo (fun (p,t) ->
flip 0.02 || (* randomly occurring blip *)
one_of (fun i -> blip_from i p t) (nplanes ()))
end;;
(* tests *)
(* First check the memoization *)
let [(0.0100000000000000019, V ())] =
exact_reify (fun () ->
let module M = BLIPMODEL(struct end) in
if M.pos (1,0) = (3,3) && M.pos (1,0) = (3,3)
then () else fail ());;
let [] =
exact_reify (fun () ->
let module M = BLIPMODEL(struct end) in
if M.pos (1,0) = (3,3) && M.pos (1,0) = (3,4)
then () else fail ());;
let [(0.0015, V ())] =
exact_reify (fun () ->
let module M = BLIPMODEL(struct end) in
if M.pos (1,0) = (3,3) && M.pos (1,1) = (3,4)
then () else fail ());;
let [(0.0288200000000000019, V true); (0.971180000000001153, V false)] =
exact_reify (fun () ->
let module M = BLIPMODEL(struct end) in
M.anyblip1 ((3,3),0));;
(* Again check memoization: facts observed once stay the same *)
let [(0.0288200000000000019, V true); (0.971180000000001153, V false)] =
exact_reify (fun () ->
let module M = BLIPMODEL(struct end) in
M.anyblip1 ((3,3),0) && M.anyblip1 ((3,3),0));;
let [(0.00191968600000000031, V true); (0.995959594000000892, V false)] =
exact_reify (fun () ->
let module M = BLIPMODEL(struct end) in
M.anyblip1 ((3,3),0) && M.anyblip1 ((3,4),1));;
(* if we multiply by 0.15 *. 0.85 (probability of exactly 1 aircraft)
and by 0.81 (prob of aircraft being detected at times 0 and 1)
we get 0.000198255571650000033, which is higher than
computed by AILog because we take into account more possibilities:
the y coordinate may increase also because the plane flies to the East
and West. The worlds presented by AILog do not show these possibilities *)
(* % observe blip(3,3,0) & blip(3,4,next(0)). *)
let query1 () =
let module M = BLIPMODEL(struct end) in
M.anyblip ((3,3),0) && M.anyblip ((3,4),1);;
(* The probability is higher than that computed by AILog: we consider
more possibilities.
*)
let [(0.00082706367283999938, V true); (0.998667405620373705, V false)] =
sample_importance (random_selector 17) 1000 query1;;
let [(0.000636272786400000141, V true); (0.998496271001613422, V false)] =
sample_importance (random_selector 19) 1000 query1;;