# Lecture 018

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

• Best: Omega(max (w/p, S))

• compiler come up with good scheduling
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