packages feed

alms-0.6.0: examples/skewness-static-bad.alms

(* Demonstrates (affine) abstract types.  Correct. *)

(*
    This is like skewness-good.alms, but it has an error in its capability
    threading, which manifests as a type error.
*)

#load "libarraycap"

open AArray

module SkewnessExample = struct
  let sum (a: (float, 't) array) (c: ('t, 'c) readcap) =
    fold (+.) 0.0 a c
  
  let mean (a: (float, 't) array) (c: ('t, 'c) readcap) =
    let (total, c) = sum a c in
      (total /. float_of_int (size a), c)
  
  let stdDev (a: (float, 't) array) (c: ('t, 'c) readcap) =
    let (mean, c) = mean a c in
    let (num, c)  = fold
                      (fun (x: float) (acc: float) ->
                         acc +. (x -. mean) ** 2.0)
                      0.0 a c in
      (sqrt (num /. float_of_int (size a)), c)
  
  let skewness (a: (float, 't) array) (c: ('t, 'c) readcap) =
    let n         = float_of_int (size a) in
    let (m, c)    = mean a c in
    let (s, c)    = stdDev a c in
    let (devs, c) = fold
                      (fun (x: float) (acc: float) ->
                         (x -. m) ** 3.0 +.  acc)
                      0.0 a c in
      (devs /. ((n -. 1.0) *. s ** 3.0), c)
  
  type transformation = T of string * (float -> float)
  
  let reduceSkewness (ts: transformation list)
                     (a: (float, 't) array)
                     (c0: 't writecap) =
    let rec replace (i: int)
                    (T(_, ft) as t: transformation)
                    (c: 't writecap)
                    : 't writecap =
      if i < size a
        then let (x, c) = get a i c in
             let c      = set a i (ft x) c in
               replace (i + 1) t c
        else c in
    (* Need type annotation for polymorphic recursion: *)
    let rec find :
        ∀ 'd. int → transformation list → ('t, 'd) readcap →
              float * transformation * ('t, 'd) readcap =
      λ ix ts c →
        match ts with
        | []  -> let (sk, c) = skewness a c in
                   (sk, T("identity", fun f -> f), c)
        | (T(_, ft) as t) ∷ ts
              -> let ((sk1, t1), (sk2, t2), c) =
                   par
                     (fun (c: ('t, 'c) readcap) -> find (ix + 1) ts c)
                     (fun (c: ('t, 'c) readcap) ->
                       let ((b, d), c) = map ft a c in
                       let (sk, d) = skewness b d in
                         (sk, t, c))
                     c
                  in if absf sk2 <. absf sk1
                       then replace 0 t1 c0; (sk2, t2, c)
                       else (sk1, t1, c) in
    let (sk, t, c) = find 0 ts c0 in
      (sk, t, replace 0 t c)
  
  let newDistribution (n: int) (T(_, gen): transformation)
                         : ex 't. (float, 't) array * 't writecap =
    let (a, c) = new n 0.0 in
      let rec loop (i: int) c =
        if i < n
          then loop (i + 1) (set a i (gen (float_of_int (i + 1))) c)
          else c in
        (a, loop 0 c)
  
  let functions (n: int) =
    [T("1",         fun (ix: float) -> 1.0)
    ,T("x",         fun (ix: float) -> ix)
    ,T("x^2",       flip ( ** ) 2.0)
    ,T("sqrt x",    sqrt)
    ,T("x^5",       flip ( ** ) 5.0)
    ,T("x^1/5",     flip ( ** ) 0.2)
    ,T("e^x",       ( ** ) 2.718)
    ,T("log x",     log)
    ,T("1/x",       (/.) 1.0)
    ,T("-x",        (-.) (float_of_int n))
    ]
  
  let testCase (n: int) (T(name, _) as t: transformation) =
    let (a, c)               = newDistribution n t in
    let (sk0, c)             = skewness a c in
    let (sk, T(name', _), c) = reduceSkewness (functions n) a c in
      putStrLn ("Distribution:      " ^ name);
      putStrLn ("Original skewness: " ^ string_of sk0);
      putStrLn ("Improved skewness: " ^ string_of sk);
      putStrLn ("Winning function:  " ^ name');
      putStrLn ""
  
  let tests (n: int) =
    foldl (fun (t: transformation) () -> testCase n t)
          () (functions n)
end

in
  SkewnessExample.tests 30