Home My Page Projects Code Snippets Project Openings diderot
Summary Activity Tracker Tasks SCM

SCM Repository

[diderot] Annotation of /branches/charisee_dev/src/compiler/basis/basis-vars.sml
ViewVC logotype

Annotation of /branches/charisee_dev/src/compiler/basis/basis-vars.sml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3604 - (view) (download)

1 : jhr 79 (* basis-vars.sml
2 :     *
3 : jhr 3349 * This code is part of the Diderot Project (http://diderot-language.cs.uchicago.edu)
4 :     *
5 :     * COPYRIGHT (c) 2015 The University of Chicago
6 : jhr 79 * All rights reserved.
7 :     *
8 :     * This module defines the AST variables for the built in operators and functions.
9 :     *)
10 :    
11 :     structure BasisVars =
12 :     struct
13 :     local
14 :     structure N = BasisNames
15 :     structure Ty = Types
16 :     structure MV = MetaVar
17 :    
18 : jhr 81 fun --> (tys1, ty) = Ty.T_Fun(tys1, ty)
19 : jhr 79 infix -->
20 :    
21 :     val N2 = Ty.DimConst 2
22 :     val N3 = Ty.DimConst 3
23 :    
24 :     (* short names for kinds *)
25 :     val TK : unit -> Ty.meta_var = Ty.TYPE o MV.newTyVar
26 : jhr 470 fun DK () : Ty.meta_var = Ty.DIFF(MV.newDiffVar 0)
27 : jhr 79 val SK : unit -> Ty.meta_var = Ty.SHAPE o MV.newShapeVar
28 :     val NK : unit -> Ty.meta_var = Ty.DIM o MV.newDimVar
29 :    
30 :     fun ty t = ([], t)
31 :     fun all (kinds, mkTy : Ty.meta_var list -> Ty.ty) = let
32 : jhr 3060 val tvs = List.map (fn mk => mk()) kinds
33 :     in
34 :     (tvs, mkTy tvs)
35 :     end
36 : jhr 79 fun allNK mkTy = let
37 : jhr 3060 val tv = MV.newDimVar()
38 :     in
39 :     ([Ty.DIM tv], mkTy tv)
40 :     end
41 : jhr 79
42 :     fun field (k, d, dd) = Ty.T_Field{diff=k, dim=d, shape=dd}
43 :     fun tensor ds = Ty.T_Tensor(Ty.Shape ds)
44 : jhr 1116 fun matrix d = tensor[d,d]
45 : jhr 79
46 :     fun monoVar (name, ty) = Var.new (name, AST.BasisVar, ty)
47 :     fun polyVar (name, scheme) = Var.newPoly (name, AST.BasisVar, scheme)
48 :     in
49 :    
50 :     (* TODO: I'm not sure how to extend + and - to fields, since the typing rules should allow
51 :     * two fields with different differentiation levels to be added.
52 :     *)
53 :    
54 :     (* overloaded operators; the naming convention is to use the operator name followed
55 :     * by the argument type signature, where
56 : jhr 3060 * i -- int
57 :     * b -- bool
58 :     * r -- real (tensor[])
59 :     * t -- tensor[shape]
60 :     * f -- field#k(d)[shape]
61 :     * s -- field#k(d)[]
62 : jhr 79 *)
63 :    
64 :     val add_ii = monoVar(N.op_add, [Ty.T_Int, Ty.T_Int] --> Ty.T_Int)
65 :     val add_tt = polyVar(N.op_add, all([SK], fn [Ty.SHAPE dd] => let
66 : jhr 3060 val t = Ty.T_Tensor(Ty.ShapeVar dd)
67 :     in
68 :     [t, t] --> t
69 :     end))
70 : jhr 470 val add_ff = polyVar(N.op_add, all([DK,NK,SK],
71 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd] => let
72 :     val f = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.ShapeVar dd}
73 :     in
74 :     [f, f] --> f
75 :     end))
76 : cchiw 2906 val add_ft = polyVar(N.op_add, all([DK,NK,SK], (* field + scalar *)
77 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd] => let
78 :     val f = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.ShapeVar dd}
79 :     val t = Ty.T_Tensor(Ty.ShapeVar dd)
80 :     in
81 :     [f, t] --> f
82 :     end))
83 : cchiw 2906 val add_tf = polyVar(N.op_add, all([DK,NK,SK], (* scalar + field *)
84 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd] => let
85 : cchiw 2906 val f = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.ShapeVar dd}
86 :     val t = Ty.T_Tensor(Ty.ShapeVar dd)
87 :     in
88 : jhr 3060 [t, f] --> f
89 : cchiw 2906 end))
90 :    
91 : jhr 79 val sub_ii = monoVar(N.op_sub, [Ty.T_Int, Ty.T_Int] --> Ty.T_Int)
92 :     val sub_tt = polyVar(N.op_sub, all([SK], fn [Ty.SHAPE dd] => let
93 : jhr 3060 val t = Ty.T_Tensor(Ty.ShapeVar dd)
94 :     in
95 :     [t, t] --> t
96 :     end))
97 : jhr 470 val sub_ff = polyVar(N.op_sub, all([DK,NK,SK],
98 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd] => let
99 : cchiw 2906 val f = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.ShapeVar dd}
100 : jhr 3060 in
101 :     [f, f] --> f
102 :     end))
103 :     val sub_ft = polyVar(N.op_sub, all([DK,NK,SK], (* field - scalar *)
104 :     fn [Ty.DIFF k, Ty.DIM d,Ty.SHAPE dd] => let
105 :     val f = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.ShapeVar dd}
106 : cchiw 2906 val t = Ty.T_Tensor(Ty.ShapeVar dd)
107 :     in
108 : jhr 3060 [f, t] --> f
109 : cchiw 2906 end))
110 : jhr 3060 val sub_tf = polyVar(N.op_sub, all([DK,NK,SK], (* scalar - field *)
111 :     fn [Ty.DIFF k, Ty.DIM d,Ty.SHAPE dd] => let
112 : cchiw 2906 val f = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.ShapeVar dd}
113 :     val t = Ty.T_Tensor(Ty.ShapeVar dd)
114 :     in
115 : jhr 3060 [t, f] --> f
116 : cchiw 2906 end))
117 :    
118 : jhr 79 (* note that we assume that operators are tested in the order defined here, so that mul_rr
119 :     * takes precedence over mul_rt and mul_tr!
120 :     *)
121 :     val mul_ii = monoVar(N.op_mul, [Ty.T_Int, Ty.T_Int] --> Ty.T_Int)
122 :     val mul_rr = monoVar(N.op_mul, [Ty.realTy, Ty.realTy] --> Ty.realTy)
123 :     val mul_rt = polyVar(N.op_mul, all([SK], fn [Ty.SHAPE dd] => let
124 : jhr 3060 val t = Ty.T_Tensor(Ty.ShapeVar dd)
125 :     in
126 :     [Ty.realTy, t] --> t
127 :     end))
128 : jhr 79 val mul_tr = polyVar(N.op_mul, all([SK], fn [Ty.SHAPE dd] => let
129 : jhr 3060 val t = Ty.T_Tensor(Ty.ShapeVar dd)
130 :     in
131 :     [t, Ty.realTy] --> t
132 :     end))
133 : jhr 470 val mul_rf = polyVar(N.op_mul, all([DK,NK,SK],
134 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd] => let
135 :     val t = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.ShapeVar dd}
136 :     in
137 :     [Ty.realTy, t] --> t
138 :     end))
139 : cchiw 3066 val mul_st = polyVar(N.op_mul, all([DK,NK,SK],
140 :     fn [Ty.DIFF k, Ty.DIM d,Ty.SHAPE dd] => let
141 :     val f = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.Shape []}
142 :     val t = Ty.T_Tensor(Ty.ShapeVar dd)
143 :     val g = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.ShapeVar dd}
144 :     in
145 :     [f, t] --> g
146 :     end))
147 :    
148 :     val mul_ts = polyVar(N.op_mul, all([DK,NK,SK],
149 :     fn [Ty.DIFF k, Ty.DIM d,Ty.SHAPE dd] => let
150 :     val f = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.Shape []}
151 :     val t = Ty.T_Tensor(Ty.ShapeVar dd)
152 :     val g = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.ShapeVar dd}
153 :     in
154 :     [t,f] --> g
155 :     end))
156 : jhr 470 val mul_fr = polyVar(N.op_mul, all([DK,NK,SK],
157 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd] => let
158 :     val t = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.ShapeVar dd}
159 :     in
160 :     [t, Ty.realTy] --> t
161 :     end))
162 : cchiw 2576 val mul_ss = polyVar(N.op_mul, all([DK,NK],
163 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d] => let
164 :     val t = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.Shape []}
165 :     in
166 :     [t, t] --> t
167 :     end))
168 : cchiw 2576 val mul_sf = polyVar(N.op_mul, all([DK,NK,SK],
169 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd] => let
170 :     val a = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.Shape []}
171 :     val b = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.ShapeVar dd}
172 :     in
173 :     [a,b] --> b
174 :     end))
175 : cchiw 2845 val mul_fs = polyVar(N.op_mul, all([DK,NK,SK],
176 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd] => let
177 :     val a = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.Shape []}
178 :     val b = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.ShapeVar dd}
179 :     in
180 :     [b,a] --> b
181 :     end))
182 : cchiw 2576
183 : jhr 79 val div_ii = monoVar(N.op_div, [Ty.T_Int, Ty.T_Int] --> Ty.T_Int)
184 :     val div_rr = monoVar(N.op_div, [Ty.realTy, Ty.realTy] --> Ty.realTy)
185 :     val div_tr = polyVar(N.op_div, all([SK], fn [Ty.SHAPE dd] => let
186 : jhr 3060 val t = Ty.T_Tensor(Ty.ShapeVar dd)
187 :     in
188 :     [t, Ty.realTy] --> t
189 :     end))
190 : jhr 470 val div_fr = polyVar(N.op_div, all([DK,NK,SK],
191 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd] => let
192 :     val t = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.ShapeVar dd}
193 :     in
194 :     [t, Ty.realTy] --> t
195 :     end))
196 : jhr 2926 val div_ss = polyVar(N.op_mul, all([DK,NK],
197 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d] => let
198 :     val t = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.Shape []}
199 :     in
200 :     [t, t] --> t
201 :     end))
202 : cchiw 2867 val div_fs = polyVar(N.op_div, all([DK,DK,NK,SK],
203 : jhr 3060 fn [Ty.DIFF k, Ty.DIFF k2, Ty.DIM d, Ty.SHAPE dd] => let
204 :     val f = Ty.T_Field{diff = Ty.DiffVar(k, 0), dim = Ty.DimVar d, shape = Ty.ShapeVar dd}
205 :     val s = Ty.T_Field{diff = Ty.DiffVar(k2, 0), dim = Ty.DimVar d, shape = Ty.Shape []}
206 :     in
207 :     [f,s] --> f
208 :     end))
209 : cchiw 2867
210 : jhr 1116 (* exponentiation; we distinguish between integer and real exponents to allow x^2 to be compiled
211 :     * as x*x.
212 :     *)
213 :     val exp_ri = monoVar(N.op_exp, [Ty.realTy, Ty.T_Int] --> Ty.realTy)
214 :     val exp_rr = monoVar(N.op_exp, [Ty.realTy, Ty.realTy] --> Ty.realTy)
215 :    
216 :     val convolve_vk = polyVar (N.op_convolve, all([DK, NK, SK],
217 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd] => let
218 :     val k = Ty.DiffVar(k, 0)
219 :     val d = Ty.DimVar d
220 :     val dd = Ty.ShapeVar dd
221 :     in
222 :     [Ty.T_Image{dim=d, shape=dd}, Ty.T_Kernel k]
223 :     --> field(k, d, dd)
224 :     end))
225 : jhr 1116 val convolve_kv = polyVar (N.op_convolve, all([DK, NK, SK],
226 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd] => let
227 :     val k = Ty.DiffVar(k, 0)
228 :     val d = Ty.DimVar d
229 :     val dd = Ty.ShapeVar dd
230 :     in
231 :     [Ty.T_Kernel k, Ty.T_Image{dim=d, shape=dd}]
232 :     --> field(k, d, dd)
233 :     end))
234 : jhr 1116
235 : jhr 2356 (* curl on 2d and 3d vector fields *)
236 :     local
237 :     val diff0 = Ty.DiffConst 0
238 :     fun field' (k, d, dd) = field(k, Ty.DimConst d, Ty.Shape(List.map Ty.DimConst dd))
239 :     in
240 :     (* FIXME: we want to be able to require that k > 0, but we don't have a way to do that! *)
241 :     val curl2D = polyVar (N.op_curl, all([DK],
242 : jhr 2948 fn [Ty.DIFF k] => let
243 : jhr 3060 val km1 = Ty.DiffVar(k, ~1)
244 :     in
245 : cchiw 2900 [field' (Ty.DiffVar(k, 0), 2, [2])] --> field' (km1, 2, [])
246 : jhr 3060 end))
247 : jhr 2356 val curl3D = polyVar (N.op_curl, all([DK],
248 : jhr 3060 fn [Ty.DIFF k] =>let
249 :     val km1 = Ty.DiffVar(k, ~1)
250 :     in
251 :     [field' (Ty.DiffVar(k, 0), 3, [3])] --> field' (km1, 3, [3])
252 :     end))
253 : jhr 2356 end (* local *)
254 :    
255 : jhr 79 val lt_ii = monoVar(N.op_lt, [Ty.T_Int, Ty.T_Int] --> Ty.T_Bool)
256 :     val lt_rr = monoVar(N.op_lt, [Ty.realTy, Ty.realTy] --> Ty.T_Bool)
257 :     val lte_ii = monoVar(N.op_lte, [Ty.T_Int, Ty.T_Int] --> Ty.T_Bool)
258 :     val lte_rr = monoVar(N.op_lte, [Ty.realTy, Ty.realTy] --> Ty.T_Bool)
259 :     val gte_ii = monoVar(N.op_gte, [Ty.T_Int, Ty.T_Int] --> Ty.T_Bool)
260 :     val gte_rr = monoVar(N.op_gte, [Ty.realTy, Ty.realTy] --> Ty.T_Bool)
261 :     val gt_ii = monoVar(N.op_gt, [Ty.T_Int, Ty.T_Int] --> Ty.T_Bool)
262 :     val gt_rr = monoVar(N.op_gt, [Ty.realTy, Ty.realTy] --> Ty.T_Bool)
263 : jhr 3060
264 : jhr 79 val equ_bb = monoVar(N.op_equ, [Ty.T_Bool, Ty.T_Bool] --> Ty.T_Bool)
265 :     val equ_ii = monoVar(N.op_equ, [Ty.T_Int, Ty.T_Int] --> Ty.T_Bool)
266 :     val equ_ss = monoVar(N.op_equ, [Ty.T_String, Ty.T_String] --> Ty.T_Bool)
267 :     val equ_rr = monoVar(N.op_equ, [Ty.realTy, Ty.realTy] --> Ty.T_Bool)
268 :     val neq_bb = monoVar(N.op_neq, [Ty.T_Bool, Ty.T_Bool] --> Ty.T_Bool)
269 :     val neq_ii = monoVar(N.op_neq, [Ty.T_Int, Ty.T_Int] --> Ty.T_Bool)
270 :     val neq_ss = monoVar(N.op_neq, [Ty.T_String, Ty.T_String] --> Ty.T_Bool)
271 :     val neq_rr = monoVar(N.op_neq, [Ty.realTy, Ty.realTy] --> Ty.T_Bool)
272 : jhr 3060
273 : jhr 1640 val neg_i = monoVar(N.op_neg, [Ty.T_Int] --> Ty.T_Int)
274 : jhr 79 val neg_t = polyVar(N.op_neg, all([SK],
275 : jhr 3060 fn [Ty.SHAPE dd] => let
276 :     val t = Ty.T_Tensor(Ty.ShapeVar dd)
277 :     in
278 :     [t] --> t
279 :     end))
280 : jhr 79 val neg_f = polyVar(N.op_neg, all([DK, NK, SK],
281 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd] => let
282 :     val k = Ty.DiffVar(k, 0)
283 :     val d = Ty.DimVar d
284 :     val dd = Ty.ShapeVar dd
285 :     in
286 :     [field(k, d, dd)] --> field(k, d, dd)
287 :     end))
288 : jhr 79
289 : jhr 1295 (* clamp is overloaded at scalars and vectors *)
290 :     val clamp_rrr = monoVar(N.fn_clamp, [Ty.realTy, Ty.realTy, Ty.realTy] --> Ty.realTy)
291 :     val clamp_vvv = polyVar (N.fn_clamp, allNK(fn tv => let
292 : jhr 3060 val t = tensor[Ty.DimVar tv]
293 :     in
294 :     [t, t, t] --> t
295 :     end))
296 : jhr 1295
297 : jhr 1116 val lerp3 = polyVar(N.fn_lerp, all([SK],
298 : jhr 3060 fn [Ty.SHAPE dd] => let
299 :     val t = Ty.T_Tensor(Ty.ShapeVar dd)
300 :     in
301 :     [t, t, Ty.realTy] --> t
302 :     end))
303 : jhr 1116 val lerp5 = polyVar(N.fn_lerp, all([SK],
304 : jhr 3060 fn [Ty.SHAPE dd] => let
305 :     val t = Ty.T_Tensor(Ty.ShapeVar dd)
306 :     in
307 :     [t, t, Ty.realTy, Ty.realTy, Ty.realTy] --> t
308 :     end))
309 : jhr 79
310 : jhr 1640 (* Eigenvalues/vectors of a matrix; we only support this operation on 2x2 and 3x3 matrices, so
311 :     * we overload the function.
312 :     *)
313 :     local
314 :     fun evals d = monoVar (N.fn_evals, [matrix d] --> Ty.T_Sequence(Ty.realTy, d))
315 :     fun evecs d = monoVar (N.fn_evecs, [matrix d] --> Ty.T_Sequence(tensor[d], d))
316 :     in
317 :     val evals2x2 = evals(Ty.DimConst 2)
318 :     val evecs2x2 = evecs(Ty.DimConst 2)
319 :     val evals3x3 = evals(Ty.DimConst 3)
320 :     val evecs3x3 = evecs(Ty.DimConst 3)
321 :     end
322 : jhr 1296
323 : jhr 79 (***** non-overloaded operators, etc. *****)
324 :    
325 : jhr 1923 (* C math functions *)
326 :     val mathFns : (MathFuns.name * Var.var) list = let
327 : jhr 3060 fun ty n = List.tabulate(MathFuns.arity n, fn _ => Ty.realTy) --> Ty.realTy
328 :     in
329 :     List.map (fn n => (n, monoVar(MathFuns.toAtom n, ty n))) MathFuns.allFuns
330 :     end
331 : jhr 1923
332 :     (* pseudo-operator for probing a field *)
333 :     val op_probe = polyVar (N.op_at, all([DK, NK, SK],
334 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd] => let
335 :     val k = Ty.DiffVar(k, 0)
336 :     val d = Ty.DimVar d
337 :     val dd = Ty.ShapeVar dd
338 :     in
339 :     [field(k, d, dd), tensor[d]] --> Ty.T_Tensor dd
340 :     end))
341 : jhr 79
342 : jhr 1383 (* differentiation of scalar fields *)
343 :     val op_D = polyVar (N.op_D, all([DK, NK],
344 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d] => let
345 :     val k0 = Ty.DiffVar(k, 0)
346 :     val km1 = Ty.DiffVar(k, ~1)
347 :     val d = Ty.DimVar d
348 :     in
349 :     [field(k0, d, Ty.Shape[])]
350 :     --> field(km1, d, Ty.Shape[d])
351 :     end))
352 : cchiw 2845
353 : cchiw 2585 (* differentiation of higher-order tensor fields *)
354 : jhr 1383 val op_Dotimes = polyVar (N.op_Dotimes, all([DK, NK, SK, NK],
355 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd, Ty.DIM d'] => let
356 :     val k0 = Ty.DiffVar(k, 0)
357 :     val km1 = Ty.DiffVar(k, ~1)
358 :     val d = Ty.DimVar d
359 :     val d' = Ty.DimVar d'
360 :     val dd = Ty.ShapeVar dd
361 :     in
362 :     [field(k0, d, Ty.ShapeExt(dd, d'))]
363 :     --> field(km1, d, Ty.ShapeExt(Ty.ShapeExt(dd, d'), d))
364 :     end))
365 : jhr 79
366 : cchiw 2585 (* divergence differentiation of higher-order tensor fields *)
367 :     val op_Ddot = polyVar (N.op_Ddot, all([DK, NK, SK, NK],
368 :     fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd, Ty.DIM d'] => let
369 :     val k0 = Ty.DiffVar(k, 0)
370 :     val km1 = Ty.DiffVar(k, ~1)
371 :     val d = Ty.DimVar d
372 :     val d' = Ty.DimVar d'
373 : jhr 2948 val dd' = Ty.ShapeVar dd
374 : cchiw 2585 in
375 : jhr 3060 [field(k0, d, Ty.ShapeExt(dd', d'))]
376 : jhr 2948 --> field(k0, d, dd')
377 : cchiw 2585 end))
378 : cchiw 2522
379 : jhr 2948 val op_norm_t = polyVar (N.op_norm, all([SK],
380 : jhr 3060 fn [Ty.SHAPE dd] => [Ty.T_Tensor(Ty.ShapeVar dd)] --> Ty.realTy))
381 : jhr 2948 val op_norm_f = polyVar (N.op_norm, all([DK, NK, SK],
382 : jhr 3060 fn [Ty.DIFF k,Ty.DIM d, Ty.SHAPE dd1] => let
383 :     val k = Ty.DiffVar(k, 0)
384 :     val d = Ty.DimVar d
385 :     val f1 = Ty.T_Field{diff = k, dim = d, shape = Ty.ShapeVar dd1}
386 :     val f2 = Ty.T_Field{diff = k, dim = d, shape = Ty.Shape []}
387 :     in
388 :     [f1] --> f2
389 :     end))
390 : jhr 79
391 :     val op_not = monoVar (N.op_not, [Ty.T_Bool] --> Ty.T_Bool)
392 :    
393 :     (* functions *)
394 : jhr 1116 local
395 :     val crossTy = let
396 : jhr 3060 val t = tensor[N3]
397 :     in
398 :     [t, t] --> t
399 :     end
400 : jhr 2948 val crossTy2 = let
401 : jhr 3060 val t = tensor[N2]
402 :     in
403 :     [t, t] --> Ty.realTy
404 :     end
405 : jhr 1116 in
406 : jhr 2948 val op_cross2_tt = monoVar (N.op_cross, crossTy2)
407 :     val op_cross3_tt = monoVar (N.op_cross, crossTy)
408 : jhr 1116 end
409 :    
410 : cchiw 2906 val op_cross2_ff = polyVar (N.op_cross, all([DK],
411 : jhr 3060 fn [Ty.DIFF k] => let
412 :     fun field' (k, d, dd) = field(k, Ty.DimConst d, Ty.Shape(List.map Ty.DimConst dd))
413 :     val k0 = Ty.DiffVar(k, 0)
414 :     val f = field' (k0, 2, [2])
415 :     val t1 = field' (k0, 2, [])
416 :     in
417 :     [f, f] --> t1
418 :     end))
419 : cchiw 2847
420 : cchiw 2906 val op_cross3_ff = polyVar (N.op_cross, all([DK],
421 : jhr 3060 fn [Ty.DIFF k] => let
422 :     fun field' (k, d, dd) = field(k, Ty.DimConst d, Ty.Shape(List.map Ty.DimConst dd))
423 :     val f = field' (Ty.DiffVar(k, 0), 3, [3])
424 :     in
425 :     [f, f] --> f
426 :     end))
427 : cchiw 2603
428 : jhr 1116 (* the inner product operator (including dot product) is treated as a special case in the
429 :     * typechecker. It is not included in the basis environment, but we define its type scheme
430 :     * here. There is an implicit constraint on its type to have the following scheme:
431 :     *
432 :     * ALL[sigma1, d1, sigma2] . tensor[sigma1, d1] * tensor[d1, sigma2] -> tensor[sigma1, sigma2]
433 :     *)
434 : cchiw 2906 val op_inner_tt = polyVar (N.op_dot, all([SK, SK, SK],
435 : jhr 3060 fn [Ty.SHAPE s1, Ty.SHAPE s2, Ty.SHAPE s3] =>
436 :     [Ty.T_Tensor(Ty.ShapeVar s1), Ty.T_Tensor(Ty.ShapeVar s2)]
437 :     --> Ty.T_Tensor(Ty.ShapeVar s3)))
438 : jhr 1116
439 : jhr 2926 val op_inner_tf = polyVar (N.op_dot, all([DK ,NK, SK, SK, SK],
440 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd1, Ty.SHAPE dd2, Ty.SHAPE dd3] => let
441 :     val k = Ty.DiffVar(k, 0)
442 :     val d = Ty.DimVar d
443 :     val t1 = Ty.T_Tensor(Ty.ShapeVar dd1)
444 :     val t2 = Ty.T_Field{diff = k, dim = d, shape = Ty.ShapeVar dd2}
445 :     val t3 = Ty.T_Field{diff = k, dim = d, shape = Ty.ShapeVar dd3}
446 :     in
447 :     [t1, t2] --> t3
448 :     end))
449 : cchiw 2584
450 : jhr 2926 val op_inner_ft = polyVar (N.op_dot, all([DK, NK, SK, SK, SK],
451 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd1, Ty.SHAPE dd2, Ty.SHAPE dd3] => let
452 :     val k = Ty.DiffVar(k, 0)
453 :     val d = Ty.DimVar d
454 :     val t1 = Ty.T_Field{diff = k, dim = d, shape = Ty.ShapeVar dd1}
455 :     val t2 = Ty.T_Tensor(Ty.ShapeVar dd2)
456 :     val t3 = Ty.T_Field{diff = k, dim = d, shape = Ty.ShapeVar dd3}
457 :     in
458 :     [t1, t2] --> t3
459 :     end))
460 : cchiw 2584
461 : cchiw 2955 val op_inner_ff = polyVar (N.op_dot, all([DK,DK, NK, SK, SK, SK],
462 : jhr 3060 fn [Ty.DIFF k1,Ty.DIFF k2, Ty.DIM d, Ty.SHAPE dd1, Ty.SHAPE dd2, Ty.SHAPE dd3] => let
463 :     val k1 = Ty.DiffVar(k1, 0)
464 : cchiw 2955 val k2 = Ty.DiffVar(k2, 0)
465 : jhr 3060 val d = Ty.DimVar d
466 :     val t1 = Ty.T_Field{diff = k1, dim = d, shape = Ty.ShapeVar dd1}
467 :     val t2 = Ty.T_Field{diff = k2, dim = d, shape = Ty.ShapeVar dd2}
468 :     val t3 = Ty.T_Field{diff = k1, dim = d, shape = Ty.ShapeVar dd3}
469 :     in
470 :     [t1, t2] --> t3
471 :     end))
472 : cchiw 2906
473 : jhr 2356 (* the colon (or double-dot) product operator is treated as a special case in the
474 :     * typechecker. It is not included in the basis environment, but we define its type
475 :     * schemehere. There is an implicit constraint on its type to have the following scheme:
476 :     *
477 :     * ALL[sigma1, d1, d2, sigma2] .
478 :     * tensor[sigma1, d1, d2] * tensor[d1, d2, sigma2] -> tensor[sigma1, sigma2]
479 :     *)
480 : cchiw 2906 val op_colon_tt = polyVar (N.op_colon, all([SK, SK, SK],
481 : jhr 3060 fn [Ty.SHAPE s1, Ty.SHAPE s2, Ty.SHAPE s3] =>
482 :     [Ty.T_Tensor(Ty.ShapeVar s1), Ty.T_Tensor(Ty.ShapeVar s2)]
483 :     --> Ty.T_Tensor(Ty.ShapeVar s3)))
484 : cchiw 2906 val op_colon_ff = polyVar (N.op_colon, all([DK, SK,NK,SK,SK],
485 : jhr 3060 fn [Ty.DIFF k,Ty.SHAPE dd1, Ty.DIM d, Ty.SHAPE dd2,Ty.SHAPE dd3] =>let
486 :     val k0 = Ty.DiffVar(k, 0)
487 :     val d' = Ty.DimVar d
488 :     val t1 = Ty.T_Field{diff = k0, dim = d', shape = Ty.ShapeVar dd1}
489 :     val t2 = Ty.T_Field{diff = k0, dim = d', shape = Ty.ShapeVar dd2}
490 :     val t3 = Ty.T_Field{diff = k0, dim = d', shape = Ty.ShapeVar dd3}
491 :     in
492 :     [t1,t2] --> t3
493 :     end))
494 : cchiw 2611
495 : cchiw 3229 val op_colon_ft = polyVar (N.op_colon, all([DK, SK,NK,SK,SK],
496 :     fn [Ty.DIFF k,Ty.SHAPE dd1, Ty.DIM d, Ty.SHAPE s2,Ty.SHAPE dd3] =>let
497 :     val k0 = Ty.DiffVar(k, 0)
498 :     val d' = Ty.DimVar d
499 :     val t1 = Ty.T_Field{diff = k0, dim = d', shape = Ty.ShapeVar dd1}
500 :     val t2 = Ty.T_Tensor(Ty.ShapeVar s2)
501 :     val t3 = Ty.T_Field{diff = k0, dim = d', shape = Ty.ShapeVar dd3}
502 :     in
503 :     [t1,t2] --> t3
504 :     end))
505 :    
506 :     val op_colon_tf = polyVar (N.op_colon, all([DK, SK,NK,SK,SK],
507 :     fn [Ty.DIFF k,Ty.SHAPE s1, Ty.DIM d, Ty.SHAPE dd2,Ty.SHAPE dd3] =>let
508 :     val k0 = Ty.DiffVar(k, 0)
509 :     val d' = Ty.DimVar d
510 :     val t1 = Ty.T_Tensor(Ty.ShapeVar s1)
511 :     val t2 = Ty.T_Field{diff = k0, dim = d', shape = Ty.ShapeVar dd2}
512 :     val t3 = Ty.T_Field{diff = k0, dim = d', shape = Ty.ShapeVar dd3}
513 :     in
514 :     [t1,t2] --> t3
515 :     end))
516 :    
517 :    
518 :    
519 :    
520 : jhr 2492 (* load image from nrrd *)
521 :     val fn_image = polyVar (N.fn_image, all([NK, SK],
522 : jhr 3060 fn [Ty.DIM d, Ty.SHAPE dd] => let
523 :     val d = Ty.DimVar d
524 :     val dd = Ty.ShapeVar dd
525 :     in
526 :     [Ty.T_String] --> Ty.T_Image{dim=d, shape=dd}
527 :     end))
528 : jhr 2492
529 : jhr 143 val fn_inside = polyVar (N.fn_inside, all([DK, NK, SK],
530 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd] => let
531 :     val k = Ty.DiffVar(k, 0)
532 :     val d = Ty.DimVar d
533 :     val dd = Ty.ShapeVar dd
534 :     in
535 :     [Ty.T_Tensor(Ty.Shape[d]), field(k, d, dd)]
536 :     --> Ty.T_Bool
537 :     end))
538 : jhr 79
539 : jhr 143 val fn_max = monoVar (N.fn_max, [Ty.realTy, Ty.realTy] --> Ty.realTy)
540 :     val fn_min = monoVar (N.fn_min, [Ty.realTy, Ty.realTy] --> Ty.realTy)
541 :    
542 : jhr 83 val fn_modulate = polyVar (N.fn_modulate, all([NK],
543 : jhr 3060 fn [Ty.DIM d] => let
544 :     val t = Ty.T_Tensor(Ty.Shape[Ty.DimVar d])
545 :     in
546 :     [t, t] --> t
547 :     end))
548 : jhr 83
549 : cchiw 3189 val fn_normalize_t = polyVar (N.fn_normalize, all([SK],
550 :     fn [Ty.SHAPE dd] => let
551 :     val t = Ty.T_Tensor(Ty.ShapeVar dd)
552 :     in
553 :     [t] --> t
554 :     end))
555 :    
556 :     val fn_normalize_f = polyVar (N.fn_normalize, all([DK,NK, SK],
557 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd1] => let
558 :     val k0 = Ty.DiffVar(k, 0)
559 :     val d' = Ty.DimVar d
560 :     val f1 = Ty.T_Field{diff = k0, dim = d', shape = Ty.ShapeVar dd1}
561 :     in
562 : cchiw 2870 [f1] --> f1
563 : jhr 3060 end))
564 : cchiw 3604 (* outer product *)
565 :     val op_outer_tt = polyVar (N.op_outer, all([SK, SK, SK],
566 :     fn [Ty.SHAPE s1, Ty.SHAPE s2, Ty.SHAPE s3] =>
567 :     [Ty.T_Tensor(Ty.ShapeVar s1), Ty.T_Tensor(Ty.ShapeVar s2)]
568 :     --> Ty.T_Tensor(Ty.ShapeVar s3)))
569 :     val op_outer_tf = polyVar (N.op_outer, all([DK,NK,SK,SK,SK],
570 :     fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd1, Ty.SHAPE dd2, Ty.SHAPE dd3] => let
571 :     val k = Ty.DiffVar(k, 0)
572 :     val d = Ty.DimVar d
573 :     val t1 = Ty.T_Tensor(Ty.ShapeVar dd1)
574 :     val t2 = Ty.T_Field{diff = k, dim = d, shape = Ty.ShapeVar dd2}
575 :     val t3 = Ty.T_Field{diff = k, dim = d, shape = Ty.ShapeVar dd3}
576 :     in
577 :     [t1, t2] --> t3
578 :     end))
579 :     val op_outer_ft = polyVar (N.op_outer, all([DK, NK, SK, SK, SK],
580 :     fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd1, Ty.SHAPE dd2, Ty.SHAPE dd3] => let
581 :     val k = Ty.DiffVar(k, 0)
582 :     val d = Ty.DimVar d
583 :     val t1 = Ty.T_Field{diff = k, dim = d, shape = Ty.ShapeVar dd1}
584 :     val t2 = Ty.T_Tensor(Ty.ShapeVar dd2)
585 :     val t3 = Ty.T_Field{diff = k, dim = d, shape = Ty.ShapeVar dd3}
586 :     in
587 :     [t1, t2] --> t3
588 :     end))
589 :     val op_outer_ff = polyVar (N.op_outer, all([DK, DK, NK, SK, SK, SK],
590 :     fn [Ty.DIFF k1,Ty.DIFF k2, Ty.DIM d, Ty.SHAPE dd1, Ty.SHAPE dd2, Ty.SHAPE dd3] => let
591 :     val k1 = Ty.DiffVar(k1, 0)
592 :     val k2 = Ty.DiffVar(k2, 0)
593 :     val d = Ty.DimVar d
594 :     val t1 = Ty.T_Field{diff = k1, dim = d, shape = Ty.ShapeVar dd1}
595 :     val t2 = Ty.T_Field{diff = k2, dim = d, shape = Ty.ShapeVar dd2}
596 :     val t3 = Ty.T_Field{diff = k1, dim = d, shape = Ty.ShapeVar dd3}
597 :     in
598 :     [t1, t2] --> t3
599 :     end))
600 : cchiw 2870
601 : jhr 91 val fn_principleEvec = polyVar (N.fn_principleEvec, all([NK],
602 : jhr 3060 fn [Ty.DIM d] => let
603 :     val d = Ty.DimVar d
604 :     in
605 :     [matrix d] --> tensor[d]
606 :     end))
607 : jhr 79
608 : cchiw 2906 val fn_trace_t = polyVar (N.fn_trace, all([NK],
609 : jhr 3060 fn [Ty.DIM d] => [matrix(Ty.DimVar d)] --> Ty.realTy))
610 : jhr 2948 val fn_trace_f = polyVar (N.fn_trace, all([DK,NK,SK],
611 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d, Ty.SHAPE dd1] => let
612 :     val k' = Ty.DiffVar(k, 0)
613 :     val d' = Ty.DimVar d
614 :     val d1 = Ty.ShapeVar dd1
615 :     val f = field(k', d', Ty.ShapeExt(Ty.ShapeExt(d1, d'), d'))
616 :     val h = field(k', d', d1)
617 :     in
618 :     [f] --> h
619 :     end))
620 : jhr 2949
621 : cchiw 2906 val fn_transpose_t = polyVar (N.fn_transpose, all([NK, NK],
622 : jhr 3060 fn [Ty.DIM d1, Ty.DIM d2] =>
623 :     [tensor[Ty.DimVar d1, Ty.DimVar d2]] --> tensor[Ty.DimVar d2, Ty.DimVar d1]))
624 : jhr 2949 val fn_transpose_f = polyVar (N.fn_transpose, all([DK,NK,NK,NK],
625 : jhr 3060 fn [Ty.DIFF k, Ty.DIM d,Ty.DIM a, Ty.DIM b] => let
626 :     val k0 = Ty.DiffVar(k, 0)
627 :     val d' = Ty.DimVar d
628 :     val a' = Ty.DimVar a
629 :     val b' = Ty.DimVar b
630 :     val f = field(k0, d', Ty.Shape[a',b'])
631 :     val h = field(k0, d', Ty.Shape[b',a'])
632 :     in
633 : jhr 2949 [f] --> h
634 : jhr 3060 end))
635 : jhr 2356
636 : cchiw 3054 (*restrict to 2x2 and 3x3*)
637 :     local
638 : cchiw 3066 val detT2 = let
639 : cchiw 3054 val t = matrix N2
640 :     in
641 : cchiw 3066 [t] --> Ty.realTy
642 : cchiw 3054 end
643 : cchiw 3055
644 : cchiw 3066 in
645 : cchiw 3055
646 : cchiw 3066 val fn_det_t2 = monoVar (N.fn_det, detT2)
647 : cchiw 3054 end
648 :    
649 : cchiw 3189 local
650 :     val detT3 = let
651 :     val t = matrix N3
652 :     in
653 :     [t] --> Ty.realTy
654 :     end
655 :    
656 :     in
657 :    
658 :     val fn_det_t3 = monoVar (N.fn_det, detT3)
659 :     end
660 :    
661 : cchiw 3066 val fn_det_f2 = polyVar (N.fn_det, all([DK],
662 :     fn [Ty.DIFF k] => let
663 :     fun field' (k, d, dd) = field(k, Ty.DimConst d, Ty.Shape(List.map Ty.DimConst dd))
664 :     val k0 = Ty.DiffVar(k, 0)
665 :     val f = field' (k0, 2, [2,2])
666 :     val s = field' (k0, 2, [])
667 :     in
668 :     [f] --> s
669 :     end))
670 :    
671 :     val fn_det_f3 = polyVar (N.fn_det, all([DK],
672 :     fn [Ty.DIFF k] => let
673 :     fun field' (k, d, dd) = field(k, Ty.DimConst d, Ty.Shape(List.map Ty.DimConst dd))
674 :     val k0 = Ty.DiffVar(k, 0)
675 :     val f = field' (k0, 3, [3,3])
676 :     val s = field' (k0, 3, [])
677 :     in
678 :     [f] --> s
679 :     end))
680 :    
681 : cchiw 3138 val fn_sqrt_f = polyVar (N.fn_sqrt, all([DK,NK],
682 :     fn [Ty.DIFF k, Ty.DIM d] => let
683 :     val k' = Ty.DiffVar(k, 0)
684 :     val d' = Ty.DimVar d
685 :     val f = field(k', d', Ty.Shape[])
686 :     in
687 :     [f] --> f
688 :     end))
689 : cchiw 3066
690 : cchiw 3138 val fn_sqrt_t = polyVar (N.fn_sqrt, all([],
691 :     fn [] => let
692 :     val t= Ty.realTy
693 :     in
694 :     [t] --> t
695 :     end))
696 :    
697 :     val fn_cos_f = polyVar (N.fn_cos, all([DK,NK],
698 :     fn [Ty.DIFF k, Ty.DIM d] => let
699 :     val k' = Ty.DiffVar(k, 0)
700 :     val d' = Ty.DimVar d
701 :     val f = field(k', d', Ty.Shape[])
702 :     in
703 :     [f] --> f
704 :     end))
705 :     val fn_acos_f = polyVar (N.fn_acos, all([DK,NK],
706 :     fn [Ty.DIFF k, Ty.DIM d] => let
707 :     val k' = Ty.DiffVar(k, 0)
708 :     val d' = Ty.DimVar d
709 :     val f = field(k', d', Ty.Shape[])
710 :     in
711 :     [f] --> f
712 :     end))
713 :    
714 :     val fn_sin_f = polyVar (N.fn_sin, all([DK,NK],
715 :     fn [Ty.DIFF k, Ty.DIM d] => let
716 :     val k' = Ty.DiffVar(k, 0)
717 :     val d' = Ty.DimVar d
718 :     val f = field(k', d', Ty.Shape[])
719 :     in
720 :     [f] --> f
721 :     end))
722 :    
723 :     val fn_asin_f = polyVar (N.fn_asin, all([DK,NK],
724 :     fn [Ty.DIFF k, Ty.DIM d] => let
725 :     val k' = Ty.DiffVar(k, 0)
726 :     val d' = Ty.DimVar d
727 :     val f = field(k', d', Ty.Shape[])
728 :     in
729 :     [f] --> f
730 :     end))
731 :    
732 :    
733 : cchiw 3440 (*Post branch split*)
734 :    
735 :     val fn_tan_f = polyVar (N.fn_tan, all([DK,NK],
736 :     fn [Ty.DIFF k, Ty.DIM d] => let
737 :     val k' = Ty.DiffVar(k, 0)
738 :     val d' = Ty.DimVar d
739 :     val f = field(k', d', Ty.Shape[])
740 :     in
741 :     [f] --> f
742 :     end))
743 :    
744 :     val fn_atan_f = polyVar (N.fn_atan, all([DK,NK],
745 :     fn [Ty.DIFF k, Ty.DIM d] => let
746 :     val k' = Ty.DiffVar(k, 0)
747 :     val d' = Ty.DimVar d
748 :     val f = field(k', d', Ty.Shape[])
749 :     in
750 :     [f] --> f
751 :     end))
752 :    
753 :    
754 :     val fn_exp_f = polyVar (N.fn_exp, all([DK,NK],
755 :     fn [Ty.DIFF k, Ty.DIM d] => let
756 :     val k' = Ty.DiffVar(k, 0)
757 :     val d' = Ty.DimVar d
758 :     val f = field(k', d', Ty.Shape[])
759 :     in
760 :     [f] --> f
761 :     end))
762 :    
763 :     val fn_exp_t = monoVar(N.fn_exp, [Ty.realTy] --> Ty.realTy)
764 :    
765 :    
766 :     val fn_pow_f = polyVar (N.fn_pow_f, all([DK,NK],
767 :     fn [Ty.DIFF k, Ty.DIM d] => let
768 :     val k' = Ty.DiffVar(k, 0)
769 :     val d' = Ty.DimVar d
770 :     val f = field(k', d', Ty.Shape[])
771 :     in
772 :     [f,Ty.T_Int] --> f
773 :     end))
774 :    
775 :    
776 : jhr 79 (* kernels *)
777 : jhr 169 (* FIXME: we should really get the continuity info from the kernels themselves *)
778 : jhr 83 val kn_bspln3 = monoVar (N.kn_bspln3, Ty.T_Kernel(Ty.DiffConst 2))
779 : jhr 169 val kn_bspln5 = monoVar (N.kn_bspln5, Ty.T_Kernel(Ty.DiffConst 4))
780 : jhr 2356 val kn_c4hexic = monoVar (N.kn_c4hexic, Ty.T_Kernel(Ty.DiffConst 4))
781 : jhr 1116 val kn_ctmr = monoVar (N.kn_ctmr, Ty.T_Kernel(Ty.DiffConst 1))
782 : jhr 83 val kn_tent = monoVar (N.kn_tent, Ty.T_Kernel(Ty.DiffConst 0))
783 : jhr 1116 (* kernels with false claims of differentiability, for pedagogy *)
784 :     val kn_c1tent = monoVar (N.kn_c1tent, Ty.T_Kernel(Ty.DiffConst 1))
785 :     val kn_c2ctmr = monoVar (N.kn_c2ctmr, Ty.T_Kernel(Ty.DiffConst 2))
786 : jhr 79
787 : jhr 1116 (***** internal variables *****)
788 : jhr 406
789 : jhr 1116 (* integer to real conversion *)
790 :     val i2r = monoVar (Atom.atom "$i2r", [Ty.T_Int] --> Ty.realTy)
791 :    
792 :     (* identity matrix *)
793 :     val identity = polyVar (Atom.atom "$id", allNK (fn dv => [] --> matrix(Ty.DimVar dv)))
794 :    
795 :     (* zero tensor *)
796 :     val zero = polyVar (Atom.atom "$zero", all ([SK],
797 : jhr 3060 fn [Ty.SHAPE dd] => [] --> Ty.T_Tensor(Ty.ShapeVar dd)))
798 : jhr 1116
799 : jhr 1640 (* sequence subscript *)
800 :     val subscript = polyVar (Atom.atom "$sub", all ([TK, NK],
801 :     fn [Ty.TYPE tv, Ty.DIM d] =>
802 :     [Ty.T_Sequence(Ty.T_Var tv, Ty.DimVar d), Ty.T_Int] --> Ty.T_Var tv))
803 : jhr 79 end (* local *)
804 : cchiw 3440
805 :    
806 :    
807 : jhr 79 end

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0