File: probability.sml

package info (click to toggle)
mlton 20210117%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 58,464 kB
  • sloc: ansic: 27,682; sh: 4,455; asm: 3,569; lisp: 2,879; makefile: 2,347; perl: 1,169; python: 191; pascal: 68; javascript: 7
file content (177 lines) | stat: -rw-r--r-- 4,583 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
(* probability.sml
 *
 * COPYRIGHT (c) 2002 Bell Labs, Lucent Technologies.
 *
 * A representation of probabilities for branch prediction.
 *)

signature PROBABILITY =
  sig

    type prob

    exception BadProb

    val never : prob	(* 0% probability *)
    val unlikely : prob	(* very close to 0% *)
    val likely : prob	(* very close to 100% *)
    val always : prob	(* 100% probability *)

    val prob : (int * int) -> prob
    val fromFreq : int list -> prob list

    val + : (prob * prob) -> prob
    val - : (prob * prob) -> prob
    val * : (prob * prob) -> prob
    val / : (prob * int) -> prob
    val not : prob -> prob		(* not p == always - p *)

    val percent : int -> prob

  (* combine a conditional branch probability (trueProb) with a
   * prediction heuristic (takenProb) using Dempster-Shafer theory.
   *)
    val combineProb2 : {trueProb : prob, takenProb : prob} -> {t : prob, f : prob}

    val toReal : prob -> real
    val toString : prob -> string

  end

structure Probability :> PROBABILITY =
  struct

    open IntInf

    val zero = fromInt 0
    val one = fromInt 1
    val two = fromInt 2
    val hundred = fromInt 100
    fun eq (a, b) = (compare(a, b) = EQUAL)

  (* Probabilities are represented as positive rationals.  Zero is
   * represented as PROB(0w0, 0w0) and one is represented as
   * PROB(0w1, 0w1).  There are several invariants about PROB(n, d):
   *	1) n <= d
   *	2) if n = 0w0, then d = 0w0 (uniqueness of zero)
   *	3) if d = 0w1, then n = 0w1 (uniqueness of one)
   *)
    datatype prob = PROB of (IntInf.int * IntInf.int)

    exception BadProb

    val never = PROB(zero, one)
    val unlikely = PROB(one, fromInt 1000)
    val likely = PROB(fromInt 999, fromInt 1000)
    val always = PROB(one, one)

    fun gcd (m, n) = if eq(n, zero) then m else gcd(n, m mod n)

    fun normalize (n, d) =
	  if eq(n, zero) then never
	  else (case compare(n, d)
	     of LESS => let
		  val g = gcd(n, d)
		  in
		    if eq(g, one)
		      then PROB(n, d)
		      else PROB(n div g, d div g)
		  end
	      | EQUAL => always
	      | GREATER => raise BadProb
	  (* end case *))
	    
    fun prob (n, d) =
	  if Int.>(n, d) orelse Int.<(n, 0) orelse Int.<=(d, 0)
	    then raise Domain
	    else normalize(fromInt n, fromInt d)

    fun add (PROB(n1, d1), PROB(n2, d2)) = normalize(d2*n1 + d1*n2, d1*d2)

    fun sub (PROB(n1, d1), PROB(n2, d2)) = let
	  val n1' = d2*n1
	  val n2' = d1*n2
	  in
	    if (n1' < n2') then raise BadProb else normalize(n1'-n2', d1*d2)
	  end

    fun mul (PROB(n1, d1), PROB(n2, d2)) = normalize (n1*n2, d1*d2)

    fun divide (PROB(n, d), m) = if Int.<=(m, 0)
	  then raise BadProb
	  else if eq(n, zero) then never
	  else normalize(n, d * fromInt m)

    fun percent n =
	  if Int.<(n, 0) then raise BadProb
	  else normalize(fromInt n, hundred)

    fun fromFreq l = let
	  fun sum ([], tot) = tot
	    | sum (w::r, tot) = if Int.<(w, 0)
		then raise BadProb
		else sum(r, fromInt w + tot)
	  val tot = sum (l, zero)
	  in
	    List.map (fn w => normalize(fromInt w, tot)) l
	  end

    fun toReal (PROB(n, d)) =
	  if eq(n, zero) then 0.0
	  else if eq(d, one) then 1.0
	  else let
	    val sz = log2 d
	    val (n, d) = if Int.>=(sz, 30)
		  then let
		    val scale = pow(two, Int.-(sz, 30))
		    val n = n div scale
		    in
		      (if n > zero then n else one, d div scale)
		    end
		  else (n, d)
	    fun toReal n = Real.fromLargeInt(toLarge n)
	    in
	      toReal n / toReal d
	    end

    fun toString (PROB(n, d)) =
	  if eq(n, zero) then "0"
	  else if eq(d, one) then "1"
	  else concat [IntInf.toString n, "/", IntInf.toString d]

  (* combine a conditional branch probability (trueProb) with a
   * prediction heuristic (takenProb) using Dempster-Shafer theory.
   * The basic equations (from Wu-Larus 1994) are:
   *    t = trueProb*takenProb / d
   *	f = ((1-trueProb)*(1-takenProb)) / d
   * where
   *	d = trueProb*takenProb + ((1-trueProb)*(1-takenProb))
   *)
    fun combineProb2 {trueProb=PROB(n1, d1), takenProb=PROB(n2, d2)} = let
	(* compute sn/sd, where
	 *    sd/sn = (trueProb*takenProb) + (1-trueProb)*(1-takenProb)
	 *)
	  val d12 = d1*d2
	  val n12 = n1*n2
	  val (sn, sd) = let
		val n = d12 + two*n12 - (d2*n1) - (d1*n2)
		in
		  (d12, n)
		end
	(* compute the true probability *)
	  val t as PROB(tn, td) = normalize(n12*sn, d12*sd)
	(* compute the false probability *)
	  val f = PROB(td-tn, td)
	  in
	    {t = t, f = f}
	  end

    fun not (PROB(n, d)) = PROB(d-n, d)

    val op + = add
    val op - = sub
    val op * = mul
    val op / = divide

  end