cost graph (series-parallel graph)
one step evaluation: (source) -> (sink)
degenerative: (source = sink)
sequential composition: G1 -connect G1 sink to G2 source-> G2
parallel composition: (fork joint parallelism)
work: total number of nodes
span: nodes of longest path
- G1 -
/ \ 0 (fork) o (joint) \ / - G2 -
Brent's Theorem: suppose an expression as work W and span S, being run on p processors
signature SEQUENCE =
sig
type 'a seq (*abstract, think of <v0, v1, v2, ..., vn> and <>*)
val empty: unit -> 'a sequence
exception Range of String
(*
REQUIRES: f total
ENSURES: f n == <f 0, ... f (n-1)>
*)
val tabulate: (int -> 'a) => int -> 'a seq
val lengt: 'a seq -> int
val nth: 'a seq -> int -> 'a
val map: ('a -> 'b) -> 'a seq -> 'b seq
val reduce: ('a * 'a -> 'a') -> 'a -> 'a seq -> 'a
val mapreduce: ('a -> 'a) -> 'b -> ('b * 'b -> 'b) -> 'a seq -> 'b
val filter: ('a -> bool) -> 'a seq -> 'a seq
end
Specification
suppose Seq :> SEQUENCE
Seq.empty () == <>, with cost graph o--o, O(1) work and span
Seq.tabulate f n == <f 0, ..., f(n-1)>
o
/ / | ... \
G0 G1 ... Gn-1
\ \ | ... /
o
where Gi is the cost graph of f i
if f is constant work and span, then Seq.tabulate has work O(n), span of O(1)
Seq.length <v0, ..., vn-1> == n, o--o, O(1) work and span
Seq.nth <v0, ..., vn-1> i == vi if 0 <= i < n, else raise Range, o--o, work span of O(1)
Seq.map f <v0, ..., vn-1> == <f vo, ... f vn-1) given f total,
o
/ / | ... \
G0 G1 ... Gn-1
\ \ | ... /
o
where Gi is the cost graph of f vi
if f is constant work and span, then Seq.map has work O(n), span of O(1)
Seq.filter has O(n) work and O(logn) span. IT DOES NOT TAKE O(n) BECAUSE WE AVE TO PUT THEM TOGETHER AGAIN
Seq.zip <> <>, Work: O(min(m, n)) Span: O(1) (because we preserve index)
Seq.append Work O(m+n), Span: O(1)
In case of reduce
reduce g z <v0, ... vn-1> == fold... (linear)
suppose g is associative (g(x, g(y, z))) == g(g(x, y), z)
write g(x, y) as x@y, then x@(y@z) == (x@y)@z
reduce g z <v0, ... vn-1> == (v0 @ v1 @, ... @ vn-1 @ z) can be grouped
reduce g z <> == z
o
/ / | ... \
G0 G1 ... Gn-1
\ \ | ... /
o o ... o
\ | ... o
o /
\ /
o (inversed tree here)
if g is O(1) work and span, Seq.reduce is O(n) work, O(logn) span
have reduce defined, we can
fun sum(S: int Seq.seq) : int = Seq.reduce (op +) 0 S
fun count(class : int Seq.seq Seq.seq) : int = sum (Seq.map sum class)
o
/ / | ... \
sum sum ... sum <- O(logn) span, O(n) work
\ \ | ... /
o
total of O(logn) span, O(n^2) work
(* rev: 'a Seq.seq * 'a Seq.seq *)
fun rev s = Seq.tabulate (fn i => (Seq.nth (Seq.length s -i-1))) n
(* maxIndex: int Seq.sqe -> int
REQUIRES: S nonempty
ENSURES: maxIndex S => the index of the largest element
COST: O(n) work, O(log n) span
*)
fun maxIndex S
= S |> Seq.enum |> Seq.reduce1 (fn ((i, x), (j, y))
=> case Int.compare (x, y) of
GREATER => (i, x)
| _ => (j, y)) |> (fn (x, _) => x)
Table of Content