-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathextending.tex
206 lines (174 loc) · 5.86 KB
/
extending.tex
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
\subsection{User-defined functions}\label{user-defined-function-section}
A user-defined function must extend \verb|blog.model.AbstractFunctionInterp|
and provide a constructor that takes a single \verb|List| argument. When
compiling the class defining the user-defined function, you must add the \bl
JAR file to the class path.
Here is an example user-defined function computing the logarithm in base 10 of
a number:
\begin{minted}{java}
package my_package;
import java.util.List;
import blog.model.AbstractFunctionInterp;
public class Log10Interp extends AbstractFunctionInterp {
public Log10Interp(List args) {
}
public Object getValue(List args) {
final double value = ((Number) args.get(0)).doubleValue();
return Math.log10(value);
}
}
\end{minted}
To use this function from a model, declare it like this:
\begin{blogcode}
fixed Real log10(Real val) = my_package.Log10Interp();
\end{blogcode}
Then \verb|log10| can be used just like any other fixed function, e.g.
\verb|query log10(100.0)|.
Make sure \verb|my_package| is on the class path. If you get an error like "No
definition found for non-random function log10", you most likely have a
class-path problem. If \verb|my_package| is in the current working directory,
you need not do anything. Otherwise, if \verb|my_package| lives at
\verb|/some/absolute/path/my_package|, launch \bl with an environment variable:
{\tt CLASSPATH=/some/absolute/path blog model.blog}.
For more advanced examples of user-defined functions, see
\verb|blog.distrib.ListInterp| and \verb|blog.distrib.TabularInterp|.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{User-defined distributions}\label{user-defined-distribution-section}
Probability distributions are implemented in Java. Distribution classes should implement the interface \verb|blog.distrib.CondProbDistrib|.
By default, the \bl engine will look up distribution classes in the package \verb|blog.distrib|. In addition, it will look up distribution classes under the default empty package.
Below is one example of a uniform distribution on Integers.
\begin{minted}{java}
package blog.distrib;
import blog.common.Util;
public class UniformInt implements CondProbDistrib {
/**
* set parameters for UniformInt
* distribution
*
* @param params
* An array of [Integer, Integer]
* <ul>
* <li>params[0]: <code>lower</code> (Integer)</li>
* <li>params[1]: <code>upper</code> (Integer)</li>
* </ul>
*
* @see blog.distrib.CondProbDistrib#setParams(java.util.List)
*/
@Override
public void setParams(Object[] params) {
if (params.length != 2) {
throw new IllegalArgumentException("expected two parameters");
}
setParams((Integer) params[0], (Integer) params[1]);
}
/**
* For a non-null value of method parameter lower, sets the
* distribution parameter <code>lower</code> to method
* parameter lower. Similarly for <code>upper</code>.
* Then checks to see if assignment of parameters is legal.
* In other words, an assignment of parameters is legal
* if <code>lower <= upper</code>.
*
* @param lower
* parameter <code>lower</code>
* @param upper
* parameter <code>upper</code>
*/
public void setParams(Integer lower, Integer upper) {
if (lower != null) {
this.lower = lower;
this.hasLower = true;
}
if (upper != null) {
this.upper = upper;
this.hasUpper = true;
}
if (this.hasLower && this.hasUpper) {
if (this.lower > this.upper) {
throw new IllegalArgumentException(
"UniformInt distribution requires that lower <= upper");
}
this.prob = 1.0 / (this.upper - this.lower + 1);
this.logProb = Math.log(this.prob);
}
}
private void checkHasParams() {
if (!this.hasLower) {
throw new IllegalArgumentException("parameter lower not provided");
}
if (!this.hasUpper) {
throw new IllegalArgumentException("parameter upper not provided");
}
}
/*
* (non-Javadoc)
*
* @see blog.distrib.CondProbDistrib#getProb(java.lang.Object)
*/
@Override
public double getProb(Object value) {
return getProb(((Integer) value).intValue());
}
/**
* Returns the probability of the UniformInt distribution having
* outcome <code>value</code>.
*/
public double getProb(int value) {
checkHasParams();
return (value >= lower) && (value <= upper) ? prob : 0;
}
/*
* (non-Javadoc)
*
* @see blog.distrib.CondProbDistrib#getLogProb(java.lang.Object)
*/
@Override
public double getLogProb(Object value) {
return getLogProb(((Integer) value).intValue());
}
/**
* Returns the log probability of the UniformInt distribution having outcome
* <code>value</code>.
*/
public double getLogProb(int value) {
checkHasParams();
return ((value >= lower) && (value <= upper)) ? logProb
: Double.NEGATIVE_INFINITY;
}
/*
* (non-Javadoc)
*
* @see blog.distrib.CondProbDistrib#sampleVal()
*/
@Override
public Object sampleVal() {
return sample_value();
}
public int sample_value() {
checkHasParams();
return lower + Util.randInt(upper - lower + 1);
}
@Override
public String toString() {
return getClass().getName();
}
/** Parameter <code>lower</code>. */
private int lower;
/** Flag indicating whether <code>lower</code> has been set. */
private boolean hasLower;
/** Parameter <code>upper</code>. */
private int upper;
/** Flag indicating whether <code>upper</code> has been set. */
private boolean hasUpper;
/**
* The probability of an outcome between <code>lower</code> and
* <code>upper</code> inclusive.
*/
private double prob;
/**
* The log probability of an outcome between <code>lower</code> and
* <code>upper</code> inclusive.
*/
private double logProb;
}
\end{minted}