158 lines · 5.1 KB · Standard ML
RawDownload
(* Array2 -- as of 1995-09-12, 1997-03-12, 1998-04-07 *) (* Representation of an m * n array: an m-vector of n-arrays (rows),   and the dimensions (m, n), m = number of rows, n = number of columns. *) (* The implementation below is pretty naive, using the Array and Vector    operations and doing more bounds checks than strictly necessary.  *) type 'a array = ('a Array.array Vector.vector * int * int) ref  datatype traversal = RowMajor | ColMajor type 'a region = { base : 'a array, row : int, col : int, 		   nrows : int option, ncols : int option} fun fromList [] = ref (Vector.fromList [], 0, 0)  | fromList (xs1 :: xsr) =    let val row1 = Array.fromList xs1	val rowr = List.map Array.fromList xsr	val cols = Array.length row1	val vec = 	    if List.all (fn r => Array.length r = cols) rowr then		Vector.fromList (row1 :: rowr)	    else		raise Size    in 	ref (vec, Vector.length vec, cols)    end fun array (m, n, x) =     ref (Vector.tabulate(m, fn _ => Array.array(n, x)), m, n); fun tabulate RowMajor (m, n, f) =     ref (Vector.tabulate(m, fn i => Array.tabulate(n, fn j => f(i,j))), m, n)  | tabulate ColMajor (m, n, f) =     if m > 0 andalso n > 0 then 	let val f00 = f(0, 0)	    val arr = Vector.tabulate(m, fn i => Array.array(n, f00))	    (* Column 0: do not apply f to (0,0) again: *)	    val _ = Vector.appi (fn (r, a) => Array.update(a, 0, f(r, 0))) 		                (arr, 1, NONE); 			    (* Remaining columns: loop, updating all rows: *)	    fun loop c = 		if c < n then  		    (Vector.appi (fn (r, a) => Array.update(a, c, f(r, c))) 		                 (arr, 0, NONE); 		     loop (c+1))		else ()	in loop 1; ref (arr, m, n) end    else	tabulate RowMajor (m, n, f) fun dimensions (ref (a,m,n)) = (m,n); fun nRows (ref (a,m,n)) = m; fun nCols (ref (a,m,n)) = n; fun sub(ref (a,m,n), i, j) = Array.sub(Vector.sub(a, i), j); fun update(ref (a,m,n), i, j, x) = Array.update(Vector.sub(a, i), j, x); fun row (ref (a, _, _), i) =     Array.extract(Vector.sub(a, i), 0, NONE); fun column (ref (a, m, n), j) =     if j<0 orelse j>=n then raise Subscript    else Vector.tabulate(m, fn k => Array.sub(Vector.sub(a, k), j)) fun fold RowMajor f b (ref (a, _, _)) =     Vector.foldl (fn (xs, res) => Array.foldl f res xs) b a  | fold ColMajor f b (ref (a, m, n)) =     let fun rows j i b = 	    if i >= m then b 	    else rows j (i+1) (f(Array.sub(Vector.sub(a, i), j), b))	fun cols j b =	    if j >= n then b 	    else cols (j+1) (rows j 0 b)    in cols 0 b end fun stop len i NONE =     if i<0 orelse i>len then raise Subscript    else len  | stop len i (SOME n) =     if i<0 orelse n<0 orelse i+n>len then raise Subscript    else i+n; fun foldi RowMajor f b { base = ref (a, m, n), row, col, nrows, ncols } =     Vector.foldli            (fn (i, xs, res) => 	       Array.foldli (fn (j,x,res) => f(i,j,x,res)) res (xs,col,ncols))	   b (a, row, nrows)  | foldi ColMajor f b { base = ref (a, m, n), row, col, nrows, ncols } =     let val stoprow = stop m row nrows	val stopcol = stop n col ncols	fun rows j i b = 	    if i >= stoprow then b 	    else rows j (i+1) (f(i, j, Array.sub(Vector.sub(a, i), j), b))	fun cols j b =	    if j >= stopcol then b 	    else cols (j+1) (rows j row b)    in cols col b end fun app RowMajor f (ref (a, _, _)) =     Vector.app (Array.app f) a  | app ColMajor f arr  =    fold ColMajor (fn (a, _) => f a) () arr fun appi RowMajor f { base = ref (a, _, _), row, col, nrows, ncols } =    Vector.appi           (fn (i, xs) => Array.appi (fn (j, x) => f(i, j, x)) (xs, col, ncols))	  (a, row, nrows)  | appi ColMajor f reg =    foldi ColMajor (fn (i, j, a, _) => f (i, j, a)) () reg fun modify RowMajor f (ref (a, _, _)) =     Vector.app (Array.modify f) a  | modify ColMajor f arr =    foldi ColMajor (fn (i, j, a, _) => update(arr, i, j, f a)) ()          {base=arr, row=0, col=0, nrows=NONE, ncols=NONE} fun modifyi RowMajor f { base = ref (a, _, _), row, col, nrows, ncols } =    Vector.appi           (fn (i, xs) => Array.modifyi (fn (j, x) => f(i, j, x)) 	                               (xs, col, ncols))	  (a, row, nrows)  | modifyi ColMajor f (reg as {base, ...}) =    foldi ColMajor (fn (i, j, a, _) => update(base, i, j, f (i, j, a))) () reg fun copy { src = { base = ref (sa, sm, sn), row = src_row, col = src_col, 		   nrows, ncols }, 	   dst = ref (da, dm, dn), dst_row, dst_col } =    let val stoprow = stop sm src_row nrows	fun bottomUp from_row to_row = 	    if from_row < src_row then ()	    else		(Array.copy { src = Vector.sub(sa, from_row), 			      si = src_col, len = ncols,			      dst = Vector.sub(da, to_row),			      di = dst_col };		 bottomUp (from_row-1) (to_row-1))	fun topDown from_row to_row = 	    if from_row >= stoprow then ()	    else		(Array.copy { src = Vector.sub(sa, from_row), 			      si = src_col, len = ncols,			      dst = Vector.sub(da, to_row),			      di = dst_col };		 topDown (from_row+1) (to_row+1))    in	if src_row <= dst_row then (* top dst overlaps with bot src; 				      copy bottom-up *)	    bottomUp (stoprow-1) (stoprow-1+dst_row-src_row)	else (* bot dst overlaps with top src; copy top-down *)	    topDown src_row dst_row    end