2 * From David McClain
's language study
.
3 * http
://www
.azstarnet
.com
/~dmcclain
/LanguageStudy
.html
5 * Stephen Weeks replaced Unsafe
.Real64Array
with Real64Array
.
12 * COPYRIGHT (c
) 1998 D
.McClain
/MCFA
13 * COPYRIGHT (c
) 1997 AT
&T Research
.
16 structure FastRealArray2
:
27 datatype traversal
= RowMajor | ColMajor
29 val array
: int * int * real -> array
30 val fromList
: real list list
-> array
31 val tabulate
: traversal
-> (int * int * (int * int -> real)) -> array
32 val sub
: array
* int * int -> real
33 val update
: array
* int * int * real -> unit
34 val dimensions
: array
-> int * int
35 val size
: array
-> int
36 val nCols
: array
-> int
37 val nRows
: array
-> int
38 val row
: array
* int -> real Vector.vector
39 val column
: array
* int -> real Vector.vector
41 val copy
: region
* array
* int * int -> unit
42 val appi
: traversal
-> (int * int * real -> unit
) -> region
-> unit
43 val app
: traversal
-> (real -> unit
) -> array
-> unit
44 val modifyi
: traversal
-> (int * int * real -> real) -> region
-> unit
45 val modify
: traversal
-> (real -> real) -> array
-> unit
46 val foldi
: traversal
-> (int*int*real*'a
-> 'a
) -> 'a
-> region
-> 'a
47 val fold
: traversal
-> (real * 'a
-> 'a
) -> 'a
-> array
-> 'a
49 val rmSub
: array
* int -> real
50 val rmUpdate
: array
* int * real -> unit
52 val unop
: array
* array
* (real -> real) -> unit
53 val unopi
: array
* array
* (real * int -> real) -> unit
54 val binop
: array
* array
* array
* (real * real -> real) -> unit
55 val binopi
: array
* array
* array
* (real * real * int -> real) -> unit
56 val fill
: array
* real -> unit
57 val fillf
: array
* (int -> real) -> unit
59 val transpose
: array
-> array
60 val extract
: region
-> array
63 val shift
: array
* int * int -> array
68 structure A
= (*Unsafe
.*)Real64Array
70 type rawArray
= A
.array
72 val unsafeUpdate
= A
.update
74 fun mkRawArray n
= A
.array (n
, 0.0)
77 type array
= {data
: rawArray
,
82 type region
= {base
: array
,
88 datatype traversal
= RowMajor | ColMajor
92 let (* going forward is twice
as fast
as backward
! *)
93 fun iter k
= if k
>= n
then ()
94 else (f(k
); iter(k
+1))
102 val arr
= mkRawArray n
104 dotimes
n (fn ix
=> unsafeUpdate(arr
,ix
,v
));
108 (* compute the index
of an array element
*)
109 fun ltu(i
,limit
) = (i
>= 0) andalso (i
< limit
)
110 fun unsafeIndex ({nrows
, ncols
, ...} : array
, i
, j
) = (i
*ncols
+ j
)
111 fun index (arr
, i
, j
) =
112 if (ltu(i
, #nrows arr
) andalso ltu(j
, #ncols arr
))
113 then unsafeIndex (arr
, i
, j
)
114 else raise General
.Subscript
115 (* row major index checking
*)
116 fun rmIndex ({nelts
,...}: array
, ix
) =
117 if ltu(ix
, nelts
) then ix
118 else raise General
.Subscript
120 val max_length
= 4096 * 4096; (* arbitrary
- but this is
128 MB
*)
122 fun chkSize (nrows
, ncols
) =
123 if (nrows
<= 0) orelse (ncols
<= 0)
124 then raise General
.Size
126 val n
= nrows
*ncols
handle Overflow
=> raise General
.Size
128 if (max_length
< n
) then raise General
.Size
else n
131 fun array (nrows
, ncols
, v
) =
133 val nelts
= chkSize (nrows
, ncols
)
135 {data
= mkArray (nelts
, v
),
136 nrows
= nrows
, ncols
= ncols
, nelts
= nelts
}
139 fun fromList
[] = raise General
.Size
140 |
fromList (row1
:: rest
) = let
141 val ncols
= List.length row1
142 fun chk ([], nrows
, l
) = (nrows
, l
)
143 |
chk (row
::rest
, nrows
, l
) = let
144 fun chkRow ([], n
, revCol
) = (
145 if (n
<> ncols
) then raise General
.Size
else ();
146 List.revAppend (revCol
, l
))
147 |
chkRow (x
::r
, n
, revCol
) = chkRow (r
, n
+1, x
::revCol
)
149 chk (rest
, nrows
+1, chkRow(row
, 0, []))
151 val (nrows
, flatList
) = chk (rest
, 1, [])
152 val nelts
= chkSize(nrows
, ncols
)
153 val arr
= mkRawArray nelts
155 |
upd(k
,v
::vs
) = (unsafeUpdate(arr
,k
,v
); upd(k
+1,vs
))
157 { data
= upd(0,List.@
(row1
, flatList
)),
163 fun tabulateRM (nrows
, ncols
, f
) =
165 val nelts
= chkSize(nrows
, ncols
)
166 val arr
= mkRawArray nelts
167 fun lp1 (i
, j
, k
) = if (i
< nrows
)
170 and lp2 (i
, j
, k
) = if (j
< ncols
)
172 unsafeUpdate(arr
, k
, f(i
, j
));
177 {data
= arr
, nrows
= nrows
, ncols
= ncols
, nelts
= nelts
}
180 fun tabulateCM (nrows
, ncols
, f
) =
182 val nelts
= chkSize(nrows
,ncols
)
183 val arr
= mkRawArray nelts
184 val delta
= nelts
- 1
185 fun lp1 (i
, j
, k
) = if (j
< ncols
)
188 and lp2 (i
, j
, k
) = if (i
< nrows
)
190 unsafeUpdate(arr
, k
, f(i
, j
));
191 lp2 (i
+1, j
, k
+ncols
))
192 else lp1 (0, j
+1, k
-delta
)
195 {data
= arr
, nrows
= nrows
, ncols
= ncols
, nelts
= nelts
}
198 fun tabulate RowMajor
= tabulateRM
199 | tabulate ColMajor
= tabulateCM
201 fun sub (a
, i
, j
) = unsafeSub(#data a
, index(a
, i
, j
))
202 fun update (a
, i
, j
, v
) = unsafeUpdate(#data a
, index(a
, i
, j
), v
)
203 fun dimensions ({nrows
, ncols
, ...}: array
) = (nrows
, ncols
)
204 fun size ({nelts
,...}: array
) = nelts
205 fun nCols (arr
: array
) = #ncols arr
206 fun nRows (arr
: array
) = #nrows arr
207 fun row ({data
, nrows
, ncols
, ...}: array
, i
) =
208 if ltu(i
, nrows
) then
213 then Vector.fromList l
214 else mkVec(j
-1, unsafeSub(data
, j
)::l
)
217 then raise General
.Subscript
218 else mkVec (stop
+ncols
-1, [])
220 else raise General
.Subscript
221 fun column ({data
, ncols
, nelts
, ...}: array
, j
) =
222 if ltu(j
, ncols
) then
226 then Vector.fromList l
227 else mkVec(i
-ncols
, unsafeSub(data
, i
)::l
)
230 then raise General
.Subscript
231 else mkVec ((nelts
- ncols
) + j
, [])
233 else raise General
.Subscript
235 datatype index
= DONE | INDX
of {i
:int, r
:int, c
:int}
237 fun chkRegion
{base
={data
, nrows
, ncols
, ...}: array
,
238 row
, col
, nrows
=nr
, ncols
=nc
}
240 fun chk (start
, n
, NONE
) =
241 if ((start
< 0) orelse (n
< start
))
242 then raise General
.Subscript
244 |
chk (start
, n
, SOME len
) =
245 if ((start
< 0) orelse (len
< 0) orelse (n
< start
+len
))
246 then raise General
.Subscript
248 val nr
= chk (row
, nrows
, nr
)
249 val nc
= chk (col
, ncols
, nc
)
251 {data
= data
, i
= (row
*ncols
+ col
), r
=row
, c
=col
, nr
=nr
, nc
=nc
}
254 fun copy (region
, dst
, dst_row
, dst_col
) =
255 raise Fail
"Array2.copy unimplemented"
258 (* this function generates a stream
of indices for the given region
in
261 fun iterateRM arg
= let
262 val {data
, i
, r
, c
, nr
, nc
} = chkRegion arg
263 val ii
= ref i
and ri
= ref r
and ci
= ref c
264 fun mkIndx (r
, c
) = let val i
= !ii
270 val r
= !ri
and c
= !ci
273 then (ci
:= c
+1; mkIndx(r
, c
))
275 then (ci
:= 0; ri
:= r
+1; iter())
282 (* this function generates a stream
of indices for the given region
in
285 fun iterateCM (arg
as {base
={ncols
, ...}, ...}) = let
286 val {data
, i
, r
, c
, nr
, nc
} = chkRegion arg
287 val delta
= nr
* ncols
- 1
288 val ii
= ref i
and ri
= ref r
and ci
= ref c
289 fun mkIndx (r
, c
) = let val i
= !ii
295 val r
= !ri
and c
= !ci
298 then (ri
:= r
+1; mkIndx(r
, c
))
300 then (ii
:= !ii
-delta
; ri
:= 0; ci
:= c
+1; iter())
307 fun appi order f region
= let
308 val (data
, iter
) = (case order
309 of RowMajor
=> iterateRM region
310 | ColMajor
=> iterateCM region
312 fun app () = (case iter()
314 | INDX
{i
, r
, c
} => (f(r
, c
, unsafeSub(data
, i
)); app())
320 fun appRM
f ({data
, nelts
, ...}: array
) =
323 if k
< nelts
then (f(unsafeSub(data
,k
));
330 fun appCM f
{data
, ncols
, nrows
, nelts
} = let
331 val delta
= nelts
- 1
332 fun appf (i
, k
) = if (i
< nrows
)
333 then (f(unsafeSub(data
, k
)); appf(i
+1, k
+ncols
))
337 if (k
< ncols
) then appf (0, k
) else ()
342 fun app RowMajor
= appRM
343 | app ColMajor
= appCM
345 fun modifyi order f region
= let
346 val (data
, iter
) = (case order
347 of RowMajor
=> iterateRM region
348 | ColMajor
=> iterateCM region
350 fun modify () = (case iter()
353 unsafeUpdate (data
, i
, f(r
, c
, unsafeSub(data
, i
)));
360 fun modifyRM
f ({data
, nelts
, ...}: array
) =
363 if k
< nelts
then (unsafeUpdate(data
,k
,f(unsafeSub(data
,k
)));
370 fun modifyCM f
{data
, ncols
, nrows
, nelts
} = let
371 val delta
= nelts
- 1
372 fun modf (i
, k
) = if (i
< nrows
)
373 then (unsafeUpdate(data
, k
, f(unsafeSub(data
, k
))); modf(i
+1, k
+ncols
))
377 if (k
< ncols
) then modf (0, k
) else ()
382 fun modify RowMajor
= modifyRM
383 | modify ColMajor
= modifyCM
385 fun foldi order f init region
= let
386 val (data
, iter
) = (case order
387 of RowMajor
=> iterateRM region
388 | ColMajor
=> iterateCM region
390 fun fold accum
= (case iter()
392 | INDX
{i
, r
, c
} => fold(f(r
, c
, unsafeSub(data
, i
), accum
))
398 fun foldRM f
init ({data
, nelts
, ...}: array
) =
400 fun foldf (k
, accum
) =
401 if k
< nelts
then foldf(k
+1,f(unsafeSub(data
,k
),accum
))
407 fun foldCM f init
{data
, ncols
, nrows
, nelts
} = let
408 val delta
= nelts
- 1
409 fun foldf (i
, k
, accum
) = if (i
< nrows
)
410 then foldf (i
+1, k
+ncols
, f(unsafeSub(data
, k
), accum
))
414 if (k
< ncols
) then foldf (0, k
, accum
) else accum
419 fun fold RowMajor
= foldRM
420 | fold ColMajor
= foldCM
423 fun transpose
{data
, nrows
, ncols
, nelts
} =
425 val dst
= mkRawArray nelts
426 val delta
= nelts
- 1
428 if k
>= nelts
then {data
= dst
,
432 else (if k
' >= nelts
then iter(k
,k
' - delta
)
433 else (unsafeUpdate(dst
,k
',unsafeSub(data
,k
));
439 fun extract (region
as {base
,row
,col
,nrows
,ncols
}) =
441 fun chk (start
,limit
,NONE
) =
442 if ltu(start
,limit
) then limit
- start
443 else raise General
.Subscript
445 |
chk (start
, limit
, SOME len
) =
446 if ltu(start
+ len
- 1, limit
) then len
447 else raise General
.Subscript
449 val nr
= chk(row
, nRows(base
), nrows
)
450 val nc
= chk(col
, nCols(base
), ncols
)
452 val dst
= mkRawArray n
453 val (data
, iter
) = iterateRM region
454 fun app (k
) = (case iter() of
460 (unsafeUpdate(dst
,k
,unsafeSub(data
,i
));
466 fun rmSub (arr
as {data
,...}: array
,ix
) =
467 unsafeSub(data
,rmIndex(arr
, ix
))
469 fun rmUpdate(arr
as {data
,...}: array
,ix
,v
) =
470 unsafeUpdate(data
,rmIndex(arr
, ix
),v
)
472 fun binop ({data
=dst
,nelts
=nelts
,...}: array
,
473 {data
=src1
,...}: array
,
474 {data
=src2
,...}: array
,
477 (fn (ix
) => unsafeUpdate(dst
,ix
,f(unsafeSub(src1
,ix
),
478 unsafeSub(src2
,ix
))))
480 fun unop ({data
=dst
,nelts
=nelts
,...}: array
,
481 {data
=src
,...}: array
,
484 (fn (ix
) => unsafeUpdate(dst
,ix
,f(unsafeSub(src
,ix
))))
486 fun binopi ({data
=dst
,nelts
=nelts
,...}: array
,
487 {data
=src1
,...}: array
,
488 {data
=src2
,...}: array
,
491 (fn ix
=> unsafeUpdate(dst
,ix
,f(unsafeSub(src1
,ix
),
495 fun unopi ({data
=dst
,nelts
=nelts
,...}: array
,
496 {data
=src
,...}: array
,
499 (fn ix
=> unsafeUpdate(dst
,ix
,f(unsafeSub(src
,ix
),ix
)))
501 fun fill ({data
=dst
,nelts
=nelts
,...}: array
,v
) =
503 (fn ix
=> unsafeUpdate(dst
,ix
,v
))
505 fun fillf ({data
=dst
,nelts
=nelts
,...}: array
,f
) =
507 (fn ix
=> unsafeUpdate(dst
,ix
,f(ix
)))
511 (* test
of Zernick phase screen E
-field generation
*)
512 (* This is
1.9 times faster than IDL
!!!! *)
515 structure F
= FastRealArray2
520 val fromInt
= LargeReal
.fromInt
522 (* setup working vectors
and arrays
*)
526 | g n l
= g (n
-1) ((f n
) :: l
)
536 (* generate an array from a scaled vector
*)
537 fun mulsv (dst
, sf
, a
) =
538 F
.unop(dst
,a
,fn(vsrc
) => sf
* vsrc
)
541 (* compute the complex exponential
of an array
*)
542 fun cisv (a
, rpart
, ipart
) =
543 (F
.unop(rpart
,a
,cos
);
547 (* accumulate scaled vectors into an array
*)
548 fun mpadd
dst (sf
, src
) =
549 F
.binop(dst
,dst
,src
,fn(vdst
,vsrc
) => vdst
+ sf
* vsrc
)
552 (* compute an E
-field from a set
of Zernike screens
*)
553 fun zern (dst
, rpart
, ipart
, coefs
, zerns
) =
554 (mulsv (dst
, hd coefs
, hd zerns
);
555 ListPair.app (mpadd dst
) (tl coefs
, tl zerns
);
556 cisv (dst
, rpart
, ipart
))
558 (* timing tests
and reporting
*)
559 fun report_times(niter
, nel
, (start
, stop
)) =
561 val secs
= Time
.-(stop
,start
)
562 val dur
= Time
.toReal(secs
) * 1.0E6
563 val ops_per_us
= ((fromInt niter
) * (fromInt nel
)) / dur
564 val ns_per_op
= 1000.0 / ops_per_us
566 print(Time
.toString (Time
.-(stop
,start
)));
568 { ops_per_us
= ops_per_us
, ns_per_op
= ns_per_op
}
571 fun time_iterations f niter
=
573 fun iter
0 = Time
.now()
574 | iter n
= (ignore (f()); iter (n
-1))
576 (Time
.now(), iter niter
)
580 report_times(niter
, nel
,
583 let val sum
= F
.array(ny
,nx
, 0.0)
584 val rpart
= F
.array(ny
,nx
, 0.0)
585 val ipart
= F
.array(ny
,nx
, 0.0)
586 val coefs
= collect
ncoefs (fn(x
) => real(1 + x
))
589 (fn(x
) => F
.tabulate F
.RowMajor
590 (ny
, nx
, fn(r
,c
) => 0.01 * real(nx
* r
+ c
)))
592 zern (sum
, rpart
, ipart
, coefs
, zerns
)
593 in if Real.abs(FastRealArray2
.sub(rpart
, 0, 1) - 0.219)
596 else raise Fail
"compiler bug"
603 fun doit n
= MSpeed
.ztest n