root/trunk/Library/Generator22D.fss @ 3917

Revision 3917, 16.4 KB (checked in by emoken, 5 months ago)

GoGs? for 2D arrays.

Line 
1(*******************************************************************************
2  Generator-of-Generators Library is copyrighted free software by Kento Emoto
3  <emoto[at]ipl.t.u-tokyo.ac.jp> developed under the collaborative
4  research on Fortress Programming Language between Sun Microsystems,
5  Inc. and the University of Tokyo. 
6 
7  You can redistribute it and/or modify it under the following
8  BSD-style license or the Sun Contributor Agreement that Kento Emoto signed.
9 
10 
11  Copyright (c) 2009 by Kento Emoto
12  All rights reserved.
13 
14  Redistribution and use in source and binary forms, with or without
15  modification, are permitted provided that the following conditions
16  are met:
17 
18      * Redistributions of source code must retain the above copyright
19        notice, this list of conditions and the following disclaimer.
20      * Redistributions in binary form must reproduce the above copyright
21        notice, this list of conditions and the following disclaimer
22        in the documentation and/or other materials provided with the
23        distribution.
24      * Neither the name of Kento Emoto nor the names of its
25        contributors may be used to endorse or promote products derived
26        from this software without specific prior written permission.
27 
28  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
30  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
32  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
35  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
36  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
37  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
38  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 
40 
41 ******************************************************************************)
42
43component Generator22D
44
45import List.{...}
46import Generator2.{...}
47export Generator22D
48
49(*---------------------------------- Rows ----------------------------------*)
50(* GoG rows generates all rows of the given 2D array. *)
51
52
53rowsImpl[\E\](g) =
54do
55  bs = g.bounds()
56  (il, jl) = bs.lower()
57  (iu, ju) = bs.upper()
58  array[\Generator[\E\]\](iu-il+1).fill(fn i =>g[(i,jl)#(1,ju-jl+1)])
59end
60
61(* Generator2 Rows *)
62object Rows[\ E, nat b0, nat s0, nat b1, nat s1 \](g : Array2[\E, b0, s0, b1, s1\]) extends Generator2[\ E \]
63  getter seed() : Generator[\ E \] = g
64  toString() : String = rowsImpl[\ E \](g).toString()
65
66  (* actual generation of the nested data structure *)
67  generate[\ R \](r : Reduction[\ R \], body : Generator[\ E \] -> R) : R = do
68        rowsImpl[\ E \](g).generate[\ R \](r, body)
69  end
70end
71
72rows[\ E, nat b0, nat s0, nat b1, nat s1 \](g : Array2[\E, b0, s0, b1, s1\]) : Rows[\E, b0, s0, b1, s1\] = Rows[\E, b0, s0, b1, s1\](g)
73
74
75(*---------------------------------- Cols ----------------------------------*)
76(* GoG cols generates all columns of the given 2D array. *)
77
78colsImpl[\E\](g) =
79do
80  bs = g.bounds()
81  (il, jl) = bs.lower()
82  (iu, ju) = bs.upper()
83  array[\Generator[\E\]\](ju-jl+1).fill(fn j =>g[(il,j)#(iu-il+1,1)])
84end
85
86(* Generator2 Cols *)
87object Cols[\ E, nat b0, nat s0, nat b1, nat s1 \](g : Array2[\E, b0, s0, b1, s1\]) extends Generator2[\ E \]
88  getter seed() : Generator[\ E \] = g
89  toString() : String = colsImpl[\ E \](g).toString()
90
91  (* actual generation of the nested data structure *)
92  generate[\ R \](r : Reduction[\ R \], body : Generator[\ E \] -> R) : R = do
93        colsImpl[\ E \](g).generate[\ R \](r, body)
94  end
95end
96
97cols[\ E, nat b0, nat s0, nat b1, nat s1 \](g : Array2[\E, b0, s0, b1, s1\]) : Cols[\E, b0, s0, b1, s1\] = Cols[\E, b0, s0, b1, s1\](g)
98
99(*---------------------------------- Rects ----------------------------------*)
100
101rectsImpl[\E\](g) =
102do
103  bs = g.bounds()
104  (il, jl) = bs.lower()
105  (iu, ju) = bs.upper()
106  s0 = iu - il + 1
107  s1 = ju - jl + 1
108  ss0 = (s0 (s0+1))/2
109  ss1 = (s1 (s1+1))/2
110  ret = array[\Generator[\E\]\](ss0, ss1).fill(
111fn (i,j) => do
112
113est_n(u) = narrow(|\ SQRT(2 u) /|)
114ss(n) = ((n-1) n) / 2
115chk(u, n) = do d = u - ss n; d > 0 AND d <= n end
116fst(a,b) = a
117snd(a,b) = b
118
119str_n(u) = do en = est_n u; cs = <|(chk(u,n),n) | n <- <|en-1, en, en+1|> |>; n = if fst cs[0] then snd cs[0] elif fst cs[1] then snd cs[1] elif fst cs[2] then snd cs[2] end; (n - 1, n - (u - ss n)) end
120
121(i0, i1) : (ZZ32, ZZ32) = str_n(ss0 - i)
122(j0, j1) : (ZZ32, ZZ32) = str_n(ss1 - j)
123
124g[(iu-i0,ju-j0)#(i1+1,j1+1)]
125end
126
127
128(* println(BIG //[r <- rows ret] (BIG |||[a <- r] a)) *)
129 ret
130end
131
132(* Generator2 Rects *)
133(* wanted to be Array2? (GGs on 2D is preferred to be Array2?) *)
134object Rects[\ E, nat b0, nat s0, nat b1, nat s1 \](g : Array2[\E, b0, s0, b1, s1\]) extends {Generator2[\ E \]}
135  getter seed() : Generator[\ E \] = g
136  toString() : String = rectsImpl[\ E \](g).toString()
137
138  (* actual generation of the nested data structure *)
139  generate[\ R \](r : Reduction[\ R \], body : Generator[\ E \] -> R) : R = do
140        rectsImpl[\ E \](g).generate[\ R \](r, body)
141  end
142
143theorems[\R, L1, L2\]() =
144<|[\((ActualReduction[\ R, L1 \], ActualReduction[\ R, L2 \], E -> R)->Boolean, (ActualReduction[\ R, L1 \], ActualReduction[\ R, L2 \], E -> R)->R)\]
145(fn (r, q, f) => conditionDistributive[\ R, L1, L2 \](r, q, f), fn (r, q, f) => efficientImplDistributive[\ R, L1, L2 \](r, q, f))
146|>
147 
148  (*--- conditions ---*)
149  conditionDistributive[\ R, L1, L2 \](q : ActualReduction[\ R, L1 \], r : ActualReduction[\ R, L2 \], f : E -> R) : Boolean = distributes(q, r)
150
151  (*--- wrapper methods for lifting/unlifting. *)
152  efficientImplDistributive[\ R, L1, L2 \](q : ActualReduction[\ R, L1 \], r : ActualReduction[\ R, L2 \], f : E -> R) = do
153    (* println("efficientImplDistributive") *)
154
155    rp = r.distribute(q)
156    i = rp.inner()
157    o = rp.outer()
158    (* we suppose that the operators i and o are lifted to L1.
159       This lifting type should be replaced with the type L of ReductionPair[\R, L\] returned by r.distribute(q).
160       But, we do not have any way to capture the type L....
161     *)
162    o.unlift(efficientImplDistributiveImpl[\L1\](o, i, fn a => i.lift(f(a))))
163  end
164  (*--- efficient implementations for some conditions ---*)
165  efficientImplDistributiveImpl[\ R \](q : Reduction[\ R \], r : Reduction[\ R \], f : E -> R) = do
166    (* defintions of operators and functions are found below. *)
167    op = MSS2DReductionAbove[\R\](q, r)
168    ot = MSS2DReductionBeside[\R\](q, r)
169
170
171    tup = op.unlift(GeneratorATWrapper(seed()).generateAT[\AnyMaybe\](op, ot, fn a => op.lift(mssBody[\R\](f(a)))))
172    tup.b
173  end
174 
175end
176
177rects[\ E, nat b0, nat s0, nat b1, nat s1 \](g : Array2[\E, b0, s0, b1, s1\]) : Rects[\E, b0, s0, b1, s1\] = Rects[\E, b0, s0, b1, s1\](g)
178
179
180
181(*-------------------- for abide-tree reductions. -------------------------*)
182trait GeneratorAT[\E\]
183  generateAT[\R\](op:Reduction[\R\], ot:Reduction[\R\], body: E->R) : R
184end
185
186object GeneratorATWrapper[\E, nat b1, nat s1, nat b2, nat s2\](x : Array2[\E, b1, s1, b2, s2\]) extends GeneratorAT[\E\]
187  generateAT[\R\](op:Reduction[\R\], ot:Reduction[\R\], body: E->R) : R = do
188    loop'(lo1:E,hi1:E,lo2:E,hi2:E) =
189      if lo1=hi1 AND lo2=hi2 then body(x[(lo1,lo2)])
190      elif lo1=hi1 then
191           split2 = partitionL((lo2 BITXOR hi2)+1)                     
192           mid2   = hi2 BITAND (BITNOT (split2-1))                     
193           ot.join(loop'(lo1,hi1,lo2,mid2-1),loop'(lo1,hi1,mid2,hi2))
194      elif lo2=hi2 then
195           split1 = partitionL((lo1 BITXOR hi1)+1)                     
196           mid1   = hi1 BITAND (BITNOT (split1-1))                     
197           op.join(loop'(lo1,mid1-1,lo2,hi2),loop'(mid1,hi1,lo2,hi2))
198      else
199           split2 = partitionL((lo2 BITXOR hi2)+1)                     
200           mid2   = hi2 BITAND (BITNOT (split2-1))                     
201           split1 = partitionL((lo1 BITXOR hi1)+1)                     
202           mid1   = hi1 BITAND (BITNOT (split1-1))                     
203           op.join(ot.join(loop'(lo1,mid1-1,lo2,mid2-1),loop'(lo1,mid1-1,mid2,hi2)),
204                   ot.join(loop'(mid1,hi1,lo2,mid2-1),loop'(mid1,hi1,mid2,hi2)))
205      end
206    loop'(b1,b1+s1-1,b2,b2+s2-1)
207  end
208  end
209
210(* for nested abide-tree reductions *)
211trait Generator2AT[\E\] extends { Generator2[\ E \], GeneratorAT[\GeneratorAT[\E\]\] }
212  generate2AT[\R\](op:Reduction[\R\], ot:Reduction[\R\], om:Reduction[\R\], od:Reduction[\R\], body: E->R) : R
213  theoremsAT[\R\]() : List[\((Reduction[\ R \], Reduction[\ R \], Reduction[\ R \], Reduction[\ R \], E -> R)->Boolean,
214                        (Reduction[\ R \], Reduction[\ R \], Reduction[\ R \], Reduction[\ R \], E -> R)->R)\] = <| |>
215  naiveImplAT[\ R \](op:Reduction[\R\], ot:Reduction[\R\], om:Reduction[\R\], od:Reduction[\R\], f : E -> R) : R =
216                            generateAT[\R\](op, ot, (fn (x) => x.generateAT[\R\](om,od,f)))
217end
218
219
220
221
222
223(*------------------------ for optimization of rects ---------------------- *)
224
225(* an exception for size-mismatching in array operations. *)
226object SizeMismatchException end
227
228(* zipwith operations *)
229zipWith(f, a, b, c) = a.ivmap(fn (ij, v) => do (i, j) = ij; f (v, b[(i,j)], c[(i,j)]) end )
230zipWith(f, a, b) = a.ivmap(fn (ij, v) => do (i, j) = ij; f (v, b[(i,j)]) end)
231
232(* generalized matrix multiplication: op and ot are used instead of + and * *)
233gemm[\T, nat s0, nat s1, nat s2 \](op:Reduction[\T\], ot:Reduction[\T\], sel:Array2[\T,0,s0,0,s1\], other: Array2[\T,0,s1,0,s2\]): Array2[\T, 0, s0, 0, s2\] = do
234        res = array2[\T, s0, s2\]()
235        mma(a:ZZ32,i:ZZ32,b:ZZ32,j:ZZ32,c:ZZ32,k:ZZ32):() =
236            if k>=i AND k>=j then
237              if k=1 then
238                pr : T = ot.join(sel.get(a,b), other.get(b,c))
239                (* If this were atomic, we could parallelize j-partition. *)
240                res.put((a,c), op.join(res.get(a,c), pr))
241              else
242                (k0,k1) = partition(k)
243                (mma(a,i,b,j,c,k0),mma(a,i,b,j,c+k0,k1))
244              end
245            elif j>=i then
246                (j0,j1) = partition(j)
247                mma(a,i,b,j0,c,k)
248                mma(a,i,b+j0,j1,c,k)
249            else
250                (i0,i1) = partition(i)
251                (mma(a,i0,b,j,c,k),mma(a+i0,i1,b,j,c,k))
252            end
253        mm(a:ZZ32,i:ZZ32,b:ZZ32,j:ZZ32,c:ZZ32,k:ZZ32):() =
254            if k>=i AND k>=j then
255              if k=1 then
256                res.put((a,c), ot.join(sel.get(a,b), other.get(b,c)))
257              else
258                (k0,k1) = partition(k)
259                (mm(a,i,b,j,c,k0),mm(a,i,b,j,c+k0,k1))
260              end
261            elif j>=i then
262                (j0,j1) = partition(j)
263                mm(a,i,b,j0,c,k)
264                mma(a,i,b+j0,j1,c,k)
265            else
266                (i0,i1) = partition(i)
267                (mm(a,i0,b,j,c,k),mm(a+i0,i1,b,j,c,k))
268            end
269        if s0=0 OR s1=0 OR s2=0 then
270          res
271        else
272          mm(0,s0,0,s1,0,s2)
273          res
274        end
275      end
276
277(* concatenation of 2D arrays: [A] BSD [B] = [A B] *)
278opr BSD[\T, nat s0, nat s1, nat s2\](x : Array2[\T, 0, s0, 0, s1\], y : Array2[\T, 0, s0, 0, s2\]) : Array2[\T, 0, s0, 0, s1 + s2\] = array2[\T, s0, s1 + s2\]().fill(fn (i, j) => if j < s1 then x[(i,j)] else y[(i, j - s1)] end)
279
280(* concatenation of 2D arrays: [A] ABV [B] = [A
281                                              B] *)
282opr ABV[\T, nat s0, nat s1, nat s2\](x : Array2[\T, 0, s0, 0, s1\], y : Array2[\T, 0, s2, 0, s1\]) : Array2[\T, 0, s0 + s2, 0, s1\] = array2[\T, s0 + s2, s1\]().fill(fn (i, j) => if i < s0 then x[(i,j)] else y[(i-s0, j)] end)
283
284(* construction of block-upper-triangular array:
285     tri(A, B, C, z) = [A B
286                        Z C] , where Z is an array filled with z (zero).
287*)
288tri[\T, nat s0, nat s1, nat s2, nat s3\](x : Array2[\T, 0, s0, 0, s1\], u: Array2[\T, 0, s0, 0, s2\], y : Array2[\T, 0, s2, 0, s3\], z : T) : Array2[\T, 0, s0 + s2, 0, s1 + s3\] = array2[\T, s0 + s2, s1 + s3\]().fill(fn (i, j) => if i < s0 AND j < s1 then x[(i,j)] elif i < s0 AND j >= s1 then u[(i, j-s1)] elif i >= s0 AND j >= s1 then y[(i-s0, j-s1)] else z end)
289
290(* generates with function an array of the same size as the given array. *)
291createArray2[\T, nat s0, nat s1\](_:Array2[\T, 0, s0, 0, s1\], f:(ZZ32,ZZ32)->T) : Array2[\T, 0, s0, 0, s1\] = array2[\T, s0, s1\]().fill(f)
292
293(* the lifted data structure for
294   oprimized computation of nested reduction with rects. *)
295trait SomeMSS2DTuple[\T\] end
296object MSS2DTuple[\T, nat s0, nat s1\](
297b : T,
298n : Array2[\T, 0, s1, 0, s1\],
299s : Array2[\T, 0, s1, 0, s1\],
300e : Array2[\T, 0, s0, 0, s0\],
301w : Array2[\T, 0, s0, 0, s0\],
302ne: Array2[\T, 0, s0, 0, s1\],
303nw: Array2[\T, 0, s0, 0, s1\],
304se: Array2[\T, 0, s0, 0, s1\],
305sw: Array2[\T, 0, s0, 0, s1\],
306c : Array2[\T, 0, s1, 0, s1\],
307r : Array2[\T, 0, s0, 0, s0\]
308) extends SomeMSS2DTuple[\T\]
309  getter size() : (ZZ32, ZZ32) = (s0, s1)
310  getter asString() : String = "(" b ", " (BIG ||| <|[\String\] "" n, "" s, "" e, "" w, "" ne, "" nw, "" se, "" sw, "" c, "" r|>) ")"
311end
312
313mssBody[\T\](v:T) : SomeMSS2DTuple[\T\] = do
314  m = array2[\T,1,1\](v)
315  MSS2DTuple[\T,1,1\](v, m, m, m, m, m, m, m, m, m, m)
316end
317
318__MSS2DTuple[\T, nat s0, nat s1\](
319b : T,
320n : Array2[\T, 0, s1, 0, s1\],
321s : Array2[\T, 0, s1, 0, s1\],
322e : Array2[\T, 0, s0, 0, s0\],
323w : Array2[\T, 0, s0, 0, s0\],
324ne: Array2[\T, 0, s0, 0, s1\],
325nw: Array2[\T, 0, s0, 0, s1\],
326se: Array2[\T, 0, s0, 0, s1\],
327sw: Array2[\T, 0, s0, 0, s1\],
328c : Array2[\T, 0, s1, 0, s1\],
329r : Array2[\T, 0, s0, 0, s0\]
330) : SomeMSS2DTuple[\T\] = MSS2DTuple[\T, s0, s1\](b, n, s, e, w, ne, nw, se, nw, c, r)
331
332object MSS2DReductionAbove[\T\](op, ot) extends { AssociativeReduction[\SomeMSS2DTuple[\T\]\] }
333  getter asString(): String = "MSS2DReductionAbove"
334  simpleJoin(x: SomeMSS2DTuple[\T\], y: SomeMSS2DTuple[\T\]): SomeMSS2DTuple[\T\] =
335  do
336    (s0x, s1x) = x.size()
337    (s0y, s1y) = y.size()
338    (* make sure s1x = s1y *)
339    if (s1x =/= s1y) then
340      throw SizeMismatchException
341    end
342    b = op.join(x.s.indices().generate[\T\](op, fn ij => ot.join(x.s[ij], y.n[ij])), op.join(x.b, y.b))
343    n = createArray2(x.n, fn ij => op.join(x.n[ij], ot.join(x.c[ij], y.n[ij])))
344    s = createArray2(x.s, fn ij => op.join(y.s[ij], ot.join(y.c[ij], x.s[ij])))
345    e = tri(x.e, gemm(op, ot, x.se, y.ne.t()), y.e, op.empty())
346    w = tri(x.w, gemm(op, ot, x.sw, y.nw.t()), y.w, op.empty())
347   
348    ne = (x.ne ABV (createArray2(y.ne, fn ij => do (i, j) = ij; ot.join(y.ne[ij], x.ne[(s0x-1, j)]) end)))
349    nw = (x.nw ABV (createArray2(y.nw, fn ij => do (i, j) = ij; ot.join(y.nw[ij], x.nw[(s0x-1, j)]) end)))
350    se = ((createArray2(x.se, fn ij => do (i, j) = ij; ot.join(x.se[ij], y.se[(0, j)]) end) ABV y.se))
351    sw = ((createArray2(x.sw, fn ij => do (i, j) = ij; ot.join(x.sw[ij], y.sw[(0, j)]) end) ABV y.sw))
352   
353    c = createArray2(x.c, fn ij => ot.join(x.c[ij], y.c[ij]))
354    r = tri(x.r, gemm(op, ot, x.r[(0,s0x-1)#(s0x, 1)], y.r[(0,0)#(1,s0y)]), y.r, op.empty())
355    __MSS2DTuple(b, n, s, e, w, ne, nw, se, nw, c, r)
356  end
357end
358
359object MSS2DReductionBeside[\T\](op, ot) extends { AssociativeReduction[\SomeMSS2DTuple[\T\]\] }
360    getter asString(): String = "MSS2DReductionBeside"
361    simpleJoin(x: SomeMSS2DTuple[\T\], y: SomeMSS2DTuple[\T\]): SomeMSS2DTuple[\T\] =
362    do
363      (s0x, s1x) = x.size()
364      (s0y, s1y) = y.size()
365      (* make sure s0x = s0y *)
366      if (s0x =/= s0y) then
367        throw SizeMismatchException
368      end
369      b = op.join(x.e.indices().generate[\T\](op, fn ij => ot.join(x.e[ij], y.w[ij])), op.join(x.b, y.b))
370
371      n = tri(x.n, gemm(op, ot, x.ne.t(), y.nw), y.n, op.empty())
372      s = tri(x.s, gemm(op, ot, x.se.t(), y.sw), y.s, op.empty())
373      e = createArray2(x.e, fn ij => op.join(y.e[ij], ot.join(y.r[ij], x.e[ij])))
374      w = createArray2(x.w, fn ij => op.join(x.w[ij], ot.join(x.r[ij], y.w[ij])))
375
376      ne = ((createArray2 (x.ne, fn ij => do (i, j) = ij; ot.join(x.ne[ij], y.ne[(i, 0)]) end) BSD y.ne))
377
378      nw = (x.nw BSD (createArray2 (y.nw, fn ij => do (i, j) = ij; ot.join(y.nw[ij], x.nw[(i, s1x-1)]) end)))
379      se = ((createArray2(x.se, fn ij => do (i, j) = ij; ot.join(x.se[ij], y.se[(i, 0)]) end) BSD y.se))
380      sw = (x.sw BSD (createArray2(y.sw, fn ij => do (i, j) = ij; ot.join(y.sw[ij], x.sw[(i, s1x-1)]) end)))
381
382
383      c = tri(x.c, gemm(op, ot, (x.c[(0,s1x-1)#(s1x,1)]), (y.c[(0,0)#(1,s1y)])), y.c, op.empty())
384      r = createArray2(x.r,fn  ij => ot.join(x.r[ij], y.r[ij]))
385
386      __MSS2DTuple(b, n, s, e, w, ne, nw, se, nw, c, r)     
387    end
388end
389
390
391
392end
Note: See TracBrowser for help on using the browser.