forked from koka-lang/koka
-
Notifications
You must be signed in to change notification settings - Fork 0
/
binarytrees.kk
141 lines (108 loc) · 3.96 KB
/
binarytrees.kk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
The Computer Language Benchmarks Game
https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
*/
module binarytrees
import std/os/env
import std/os/task
import std/num/int32
type tree
Node( left : tree, right : tree )
Tip
// make a perfectly balanced binary tree of `depth` using FBIP
// to use no extra stack space.
type builder
Top
BuildRight( depth : int, up : builder )
BuildNode( left : tree, up : builder )
// using mutual recursion
fun make-down( depth : int, builder : builder ) : div tree
if depth > 0
then make-down( depth - 1, BuildRight(depth - 1, builder))
else make-up( Node(Tip,Tip), builder)
fun make-up( t : tree, builder : builder ) : div tree
match builder
BuildRight(depth, up) -> make-down( depth, BuildNode(t, up))
BuildNode(l, up) -> make-up( Node(l, t), up)
Top -> t
// using a single tail recursive definition
type direction
Down( depth : int )
Up( t : tree )
fun make-fbip( dir : direction, builder : builder) : div tree
match dir
Down(depth) -> if depth > 0
then make-fbip(Down(depth - 1), BuildRight(depth - 1, builder))
else make-fbip(Up(Node(Tip,Tip)), builder)
Up(t) -> match builder
BuildRight(depth, up) -> make-fbip(Down(depth), BuildNode(t, up))
BuildNode(l, up) -> make-fbip(Up(Node(l, t)), up)
Top -> t
// make a perfectly balanced binary tree of `depth`
fun make-rec( depth : int ) : div tree
if depth > 0
then Node( make-rec(depth - 1), make-rec(depth - 1) )
else Node( Tip, Tip )
fun make( depth : int ) : div tree
make-rec(depth)
// make-fbip(Down(depth), Top)
// make-down( depth, Top )
// FBIP in action: use a visitor to run the checksum tail-recursively
type visit
Done
NodeR( right : tree, v : visit )
// tail-recursive checksum
fun checkv( t : tree, v : visit, acc : int ) : div int
match t
Node(l,r) -> checkv( l, NodeR(r,v), acc.inc)
Tip -> match v
NodeR(r,v') -> checkv( r, v', acc)
Done -> acc
// normal checksum
fun checkr( t : tree ) : div int
match t
Node(l,r) -> l.checkr + r.checkr + 1
Tip -> 0
fun check( t : tree ) : div int
checkv(t, Done, 0)
//t.checkr
// generate `count` trees of `depth` and return the total checksum
fun sum-count( count : int, depth : int ) : div int
fold-int(count+1,0) fn(i,csum)
// csum + make(depth).check
csum + make(depth).check
// parallel sum count: spawn up to `n` sub-tasks to count checksums
fun psum-count( count : int, depth : int ) : pure int
val n = 8
val partc = count / n
val rest = count % n
val parts = list(1,n, fn(i) task{ sum-count( partc, depth ) })
sum-count(rest, depth) + parts.await.sum
// for depth to max-depth with stride 2, process
// many trees of size depth in parallel and compute the total checksum
fun gen-depth( min-depth : int, max-depth : int ) : pure list<(int,int,promise<int>)>
list(min-depth, max-depth, 2) fn(d)
val count = 2^(max-depth + min-depth - d) // todo: ensure fast 2^n operation
(count, d, task{ psum-count(count, d) })
//(count, d, task{ sum-count(count, d) } ) // one task per depth
// show results
fun show( msg : string, depth : int, check : int ) : console ()
println(msg ++ " of depth " ++ depth.show ++ "\t check: " ++ check.show)
// main
pub fun main()
// task-set-default-concurrency(8);
val n = get-args().head.default("").parse-int.default(21)
val min-depth = 4
val max-depth = max(min-depth + 2, n)
// allocate and free the stretch tree
val stretch-depth = max-depth.inc
show( "stretch tree", stretch-depth, make(stretch-depth).check )
// allocate long lived tree
// val long = make(max-depth)
val long = make(max-depth)
// allocate and free many trees in parallel
val trees = gen-depth( min-depth, max-depth )
trees.foreach fn((count,depth,csum))
show( count.show ++ "\t trees", depth, csum.await )
// and check if the long lived tree is still good
show( "long lived tree", max-depth, long.check )