tim sheard oregon graduate institute
DESCRIPTION
Fundamentals of. Staged Computation. Tim Sheard Oregon Graduate Institute. Lecture 3: More Examples. CSE 510 Section FSC Winter 2004. Assignments. The paper DSL Implementation Using Staging and Monads is now officially assigned. See the web page to obtain a copy. - PowerPoint PPT PresentationTRANSCRIPT
Tim SheardOregon Graduate Institute
Lecture 3: More Examples
CSE 510 Section FSCCSE 510 Section FSC
Winter 2004Winter 2004
2Cse583 Winterl 2002
Assignments
The paper DSL Implementation Using Staging and Monads is now officially assigned. See the web page to obtain a copy. A volunteer presenter is needed to
present the paper next Monday.
Homework 2, due in one week, is now assigned. See webpage for details Due in one week, Monday Jan 18
3Cse583 Winterl 2002
An Interesting Note
Some functions are code transformers plus : int -> <int> -> <int> plus x ycode = < ~(lift x) + ~ycode >
Others are code generators plus' : int -> <int -> int> plus' x = <fn y => ~(lift x) + y>
When do we use one? When do we use the other? Are they equivalent?
4Cse583 Winterl 2002
Transformers to generators
Code transformers can be made code generators with a “trick”
fun plus’’ n = <fn y => ~(plus n <y>)>;
-| plus’’ 3;
val it =
<(fn a = 3 %+ a)>
: <int -> int>
5Cse583 Winterl 2002
Another example: two versions
fun add3 0 y = y
| add3 n y = < 1 + ~(add3 (n-1) y)>;
fun add4 0 = <fn y => y>
| add4 n = <fn y => 1 + ~(add4 (n-1)) y>;
6Cse583 Winterl 2002
Exponentially large generated programs
fun even x = (x mod 2) = 0;
fun filter p [] = <[]>
| filter p (x::xs) =
<if ~p ~(lift x)
then ~(filter p xs)
else ~(lift x) :: ~(filter p xs)>;
-| filter <even> [3];
val it =
<if %even 3 then [] else [3]>
: <int list>
Note the repeated, related (here identical)
, recursive calls
7Cse583 Winterl 2002
But let the list grow-| filter <even> [1,2,3,4];val it = <if %even 1 then if %even 2 then if %even 3 then if %even 4 then [] else [4] else 3 :: if %even 4 then [] else [4] else 2 :: if %even 3 then if %even 4 then [] else [4] else 3 :: if %even 4 then [] else [4] else 1 :: if %even 2 then if %even 3 then if %even 4 then [] else [4] else 3 :: if %even 4 then [] else [4] else 2 :: if %even 3 then if %even 4 then [] else [4] else 3 :: if %even 4 then [] else
[4]> : <int list>
8Cse583 Winterl 2002
Use let to share callsfun filter p [] = <[]>
| filter p (x::xs) =
<let val ys = ~(filter p xs)
in if ~p ~(lift x)
then ys
else ~(lift x) :: ys end>;
val ex2 = filter <even> [1,2,3,4];
-| val ex2 =
<let val a = []
val b = if %even 4 then a else 4 :: a
val c = if %even 3 then b else 3 :: b
val d = if %even 2 then c else 2 :: c
in if %even 1 then d else 1 :: d end>
9Cse583 Winterl 2002
Staged Shortest Path
Given a directed weighted graph G=(V,E)Two nodes a,b in V, The shortest path algorithm finds the minimum weighted path in G from the source a to the destination b.Where the weights are given by a weight function W
10Cse583 Winterl 2002
Representing Graphsfun g x =
case x of
1 => [2]
| 2 => [3,4]
| 3 => [5]
| 4 => [1,2,5]
| 5 => [4]
| _ => [];
3
2
1 4
5
11Cse583 Winterl 2002
Structure of functionfun shortestPath succ source dest marked weight = . . .
succ is the function associating to a vertex a list of successor vertexes, and encodes the topology of the graph
source is the source vertex; dest is the destination vertex; marked indicates which nodes have already
been visited by the algorithm; (weight x y) indicates the weight of the
edge (x,y).
12Cse583 Winterl 2002
Helper functions(* min : int -> int -> int *)fun min x z = if x '<' z then x else z ;
(* minimum : int list -> int *)fun minimum (x::xs) = (case xs of [] => x | _ => min x (minimum xs));
(* map : ('b -> 'a) -> 'b list -> 'a list *)fun map f [] = [] | map f (a::b) = (f a)::(map f b);
(* mem : int -> int list -> bool *)fun mem x [] = false | mem x (a::b) = if a=x then true else mem x b;
(* minus : int list -> int list -> int list *)fun minus [] ys = [] | minus (a::b) ys = if mem a ys then minus b ys else a::(minus b ys);
13Cse583 Winterl 2002
shortestPathfun shortestPath succ source dest marked weight =if source = dest then 0 else let val marked2 = (source::marked) val explore = (minus (succ source) marked2) fun short x = shortestPath succ x dest marked2 weight val path_weights = map (fn node => (short node) + (weight source node)) explore in case path_weights of [] => infinity | _ => (minimum path_weights) end;
14Cse583 Winterl 2002
Exampleval ex1 =
let fun weight x y = 1
in shortestPath g 3 2 [] weight end;
-| val ex1 = 3 : int3
2
1 4
5
15Cse583 Winterl 2002
Staging shortestPath The graph is knownThe source and destination are knownThe weight function is dynamic and won’t be known until later.
shortestPath :
graph -> int -> int -> int list ->
(int -> int -> int) -> int
shortestPath2 :
graph -> int -> int -> int list ->
<(int -> int -> int) -> int>
16Cse583 Winterl 2002
Stage helper functions
Staging the minimum function
liftMinimum : <int> list -> <int>
fun liftMinimum x =
case x of
[] => <infinity>
| (c::cs) => <min ~c ~(liftMinimum cs)>;
17Cse583 Winterl 2002
shortestPath2fun shortestPath2 succ source dest marked = <fn weight => ~(if source = dest then <0> else let val marked2 = source::marked val explore = (minus (succ source) marked) fun short x = shortestPath2 succ x dest marked2 val path_weights = map (fn node => < (~(short node) weight) + (weight ~(lift source) ~(lift node)) > ) explore in (liftMinimum path_weights) end ) >;
Note shortestPath2 is
in generator style
18Cse583 Winterl 2002
Results-| val ex2 = (shortestPath2 g 4 2 []);
val ex2 =
<(fn a =>
%min (%min (0 %+ a 1 2) (%infinity %+ a 4 1))
(%min (0 %+ a 4 2)
(%min (%infinity %+ a 4 5)
%infinity)))>
: <(int -> int -> int) -> int>
3
2
1 4
5
19Cse583 Winterl 2002
Unnest the calls to min
fun liftMinimum x =
case x of
[] => <infinity>
| [x] => x
| ( <infinity> :: cs) => liftMinimum cs
| (c::cs) => <let val y = ~(liftMinimum cs)
val z = ~c
in min z y end>;
Note special case for
singleton list
20Cse583 Winterl 2002
shortestPath2 againfun shortestPath2 succ source dest marked = <fn weight =>
~(if source = dest
then <0>
else let val marked2 = source::marked
val explore = (minus (succ source) marked)
fun short x = shortestPath2 succ x dest marked2
val path_weights =
map (fn node =>
let val recall = < ~(short node) weight>
val wght = <weight ~(lift source) ~(lift node)>
in <let val q = ~recall in q + ~wght end>
end)
explore
in (liftMinimum path_weights) end
) >;
Note the generated let
21Cse583 Winterl 2002
Results
val ex2 = (shortestPath2 g 4 2 []);
-| val ex2 =
<(fn a =>
let val b = %infinity %+ a 4 5
val c = 0 %+ a 4 2
val d = %min c b
val e = 0 %+ a 1 2
val f = e %+ a 4 1
in %min f d end)>
: <(int -> int -> int) -> int>
3
2
1 4
5
22Cse583 Winterl 2002
Extended example 2
Staged merge function for sorted listsUn-staged version
fun merge xs ys =
case xs of
[] => ys
| (z::zs) => case ys of
[] => xs
| w::ws => if z '<' (w:int)
then z::(merge zs ys)
else w::(merge xs ws);
Suppose xs is static and ys is dynamic
23Cse583 Winterl 2002
First staged attempt fun merge2 xs =
<fn ys =>
~(case xs of
[] => <ys>
| (z::zs) =>
<case ys of
[] => ~(lift xs)
| (w::ws) =>
if z '<' (w:int)
then z::(~(merge2 zs) ys)
else w::(~(merge2 xs) ws)
>)>;
Goes into an infinite loop. Why?
24Cse583 Winterl 2002
Second AttemptFirst some helper functions
fun reverse [] ys = ys
| reverse (x::xs) ys = (reverse xs (x::ys));
fun split2 (n:int) xs (small,big) =
case xs of
[] => (reverse small [], reverse big [])
| (z::zs) => if z '>' n
then split2 n zs (small,z::big)
else split2 n zs (z::small,big);
fun split n l = (split2 n l ([],[]));
25Cse583 Winterl 2002
Unstaged version using the helper functions
fun merge3 xs ys =
case xs of
[] => ys
| z::zs =>
(case ys of
[] => xs
| w::ws =>
if z '<' w
then z::(merge3 zs ys)
else let val (u,v) = split z ys
in
append u (z::(merge3 zs v))
end
);split avoids recursive
call on xs
u is all elements of
ys less than z
26Cse583 Winterl 2002
Staged Versionfun merge4 xs = <fn ys => ~(case xs of [] => <ys> | (b::bs) => <case ys of [] => ~(lift xs) | (w::ws) => if (~(lift b)) '<' w then (~(lift b))::(~(merge4 bs) ys) else let val (low,high) = split (~(lift b)) ys in append low (~(lift b)::(~(merge4 bs) high)) end >) >;
27Cse583 Winterl 2002
Not so-good, Generated code
-| merge4 [2,5];val it = <(fn a => (case a of [] => [2,5] | (c::b) => if 2 %'<' c then 2 :: (case a of [] => [5] | (k::j) => if 5 %'<' k then 5 :: a else let val (m,l) = %split 5 a in %append m (5 :: l) end) else let val (e,d) = %split 2 a in %append e (2 :: (case d of [] => [5] | (g::f) => if 5 %'<' g then 5 :: d else let val (i,h) = %split 5 d in %append i (5 :: h) end)) end))> : <int list -> int list>
28Cse583 Winterl 2002
Improve by use transformer style use let to share recursive call
fun merge5 xs ys = case xs of [] => ys| (b::bs) => <case ~ys of [] => ~(lift xs) | (w::ws) => let val tail = ~(merge5 bs ys) val (low,high) = split (~(lift b)) ~ys in if (~(lift b)) '<' w then (~(lift b)):: tail else append low (~(lift b):: tail) end >;fun f1 xs = <fn ys => ~(merge5 xs <ys>)>;
29Cse583 Winterl 2002
Better code-| f1 [2,3];val it = <(fn a => (case a of [] => [2,3] | (c::b) => let val d = case a of [] => [3] | (f::e) => let val (h,g) = %split 3 a in if 3 %'<' f then 3 :: a else %append h (3 :: a) end) val (j,i) = %split 2 a in if 2 %'<' c then 2 :: d else %append j (2 :: d) end))>
30Cse583 Winterl 2002
ReviewMultiple stage programs require nested brackets. Transformer style is often useful.Staged helper functions are often necessary.Generated programs must follow all paths of a generated if or case, even if the unstaged version will follow only one path.
Leads to possiblility of exponentially growing code. Can cause the generator not to terminate if recursive call
at first level doesn’t “get smaller”, even though it gets smaller (in the second stage) in the unstaged program.
Use let to share similar or related code to avoid this blowup.
Use let to avoid deeply nested function calls. Simplifies the structure, and won’t blow up the object level compiler by generating code in weird ways.