/
flatten.jl
122 lines (99 loc) · 3.3 KB
/
flatten.jl
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
facts("Flatten") do
a = Signal(0)
b = Signal(1)
c = Signal(a)
d = flatten(c)
cnt = foldp((x, y) -> x+1, 0, d)
context("Signal{Signal} -> flat Signal") do
# Flatten implies:
@fact value(c) --> a
@fact value(d) --> value(a)
end
context("Initial update count") do
@fact value(cnt) --> 0
end
context("Current signal updates") do
push!(a, 2)
step()
@fact value(cnt) --> 1
@fact value(d) --> value(a)
end
context("Signal swap") do
push!(c, b)
step()
@fact value(cnt) --> 2
@fact value(d) --> value(b)
push!(a, 3)
step()
@fact value(cnt) --> 2
@fact value(d) --> value(b)
push!(b, 3)
step()
@fact value(cnt) --> 3
@fact value(d) --> value(b)
end
context("Subtle sig swap issue") do
# When a node, a map (e) in this case, has a flatten as a parent, but also
# a signal that is the flatten parent sigsig's (c's) current value ("a" here)
# then when the sigsig gets pushed another value, you want the map to
# still update on changes to a, even after the map is "rewired" when a
# new value is pushed to c.
a = Signal(1)
b = Signal(2)
c = Signal(a)
d = flatten(c)
e = map(*, a, d) #e is dependent on "a" directly and through d
@fact value(e) --> 1
push!(a, 3)
step()
@fact value(a) --> 3
@fact value(d) --> 3
@fact value(e) --> 9
push!(c, b)
@fact value(e) --> 9 # no change until step
step()
@fact value(d) --> 2 # d now takes b's value
@fact value(e) --> 6 # e == d * a == 2 * 3 == 6
# the push!(c, b) should have triggered a "rewiring" of the graph
# so that updates to b affect d and e
push!(b, 9)
step()
@fact value(d) --> 9 # d now takes b's value
@fact value(e) --> 27 # e == d * a == 9 * 3 == 27
# changes to a should still affect e (but not d)
push!(a, 4)
@fact value(e) --> 27 # no change until step
step()
@fact value(a) --> 4
@fact value(d) --> 9 # no change to d
@fact value(e) --> 36 # a*d == 4 * 9
@fact queue_size() --> 0
end
context("Sigsig's value created after SigSig") do
# This is why we need bind! in flatten implementation rather than just
# setting the flatten's parents to (input, current_node) every time
# input updates. That won't work if the current_node was created after
# the flatten (e.g. in the below after pushing a new value to `a`),
# because updates to the current_node happen further down the `nodes`
# list than the flatten, so the flatten doesn't get updated.
a = Signal(number())
local b
c = foreach(a) do av
b = Signal(av)
foreach(identity, b)
end
d = flatten(c)
b_orig = b
@fact d.value --> a.value
push!(b, number())
step()
@fact d.value --> b.value
push!(a, number())
step()
@fact d.value --> a.value
@fact b_orig --> not(b)
push!(b, number())
step()
@fact d.value + 1 --> b.value + 1
end
end