~ubuntu-branches/ubuntu/lucid/pdl/lucid

« back to all changes in this revision

Viewing changes to Basic/Pod/Dataflow.pod

  • Committer: Bazaar Package Importer
  • Author(s): Ben Gertzfield
  • Date: 2002-04-08 18:47:16 UTC
  • Revision ID: james.westby@ubuntu.com-20020408184716-0hf64dc96kin3htp
Tags: upstream-2.3.2
ImportĀ upstreamĀ versionĀ 2.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
=head1 NAME
 
2
 
 
3
PDL::Dataflow -- description of the dataflow philosophy
 
4
 
 
5
=head1 SYNOPSIS
 
6
 
 
7
        perldl> $a = zeroes(10);
 
8
        perldl> $b = $a->slice("2:4:2");
 
9
        perldl> $b ++;
 
10
        perldl> print $a;
 
11
        [0 0 1 0 1 0 0 0 0 0]
 
12
 
 
13
 
 
14
=head1 WARNING
 
15
 
 
16
Dataflow is very experimental. Many features of it are disabled
 
17
for 2.0, particularly families for one-directional
 
18
dataflow. If you wish to use one-directional dataflow for
 
19
something, please contact the author first and we'll work out
 
20
how to make it functional again.
 
21
 
 
22
Two-directional dataflow (which implements ->slice() etc.)
 
23
is fully functional, however. Just about any function which
 
24
returns some subset of the values in some piddle will make a binding
 
25
so that
 
26
 
 
27
        $a = some piddle
 
28
        $b = $a->slice("some parts");
 
29
        $b->set(3,3,10);
 
30
 
 
31
also changes the corresponding element in $a. $b has become effectively
 
32
a window to some subelements of $a. You can also define your own routines
 
33
that do different types of subsets. If you don't want $b to be a window
 
34
to $a, you must do
 
35
 
 
36
        $b = $a->slice("some parts")->copy;
 
37
 
 
38
The copying turns off all dataflow between the two piddles.
 
39
 
 
40
The difficulties with one-directional
 
41
dataflow are related to sequences like
 
42
 
 
43
        $b = $a + 1;
 
44
        $b ++;
 
45
 
 
46
where there are several possible outcomes and the semantics get a little
 
47
murky.
 
48
 
 
49
=head1 DESCRIPTION
 
50
 
 
51
Dataflow is new to PDL2.0. The basic philosophy
 
52
behind dataflow is that
 
53
 
 
54
        > $a = pdl 2,3,4;
 
55
        > $b = $a * 2;
 
56
        > print $b
 
57
        [2 3 4]
 
58
        > $a->set(0,5);
 
59
        > print $b;
 
60
        [10 3 4]
 
61
 
 
62
should work. It doesn't. It was considered that doing this
 
63
might be too confusing for novices and occasional users of the language.
 
64
Therefore, you need to explicitly turn on dataflow, so
 
65
 
 
66
        > $a = pdl 2,3,4;
 
67
        > $a->doflow();
 
68
        > $b = $a * 2;
 
69
        ...
 
70
 
 
71
produces the (un)expected result. The rest of this documents
 
72
explains various features and details of the dataflow implementation.
 
73
 
 
74
=head1 Lazy evaluation
 
75
 
 
76
When you calculate something like the above
 
77
 
 
78
        > $a = pdl 2,3,4;
 
79
        > $a->doflow();
 
80
        > $b = $a * 2;
 
81
 
 
82
nothing will have been calculated at this point. Even the memory for
 
83
the contents of $b has not been allocated. Only the command
 
84
 
 
85
        > print $b
 
86
 
 
87
will actually cause $b to be calculated. This is important to bear
 
88
in mind when doing performance measurements and benchmarks as well
 
89
as when tracking errors.
 
90
 
 
91
There is an explanation for this behaviour: it may save cycles
 
92
but more importantly, imagine the following:
 
93
 
 
94
        > $a = pdl 2,3,4;
 
95
        > $b = pdl 5,6,7;
 
96
        > $c = $a + $b;
 
97
        ...
 
98
        > $a->resize(4);
 
99
        > $b->resize(4);
 
100
        > print $c;
 
101
 
 
102
Now, if $c were evaluated between the two resizes, an error condition
 
103
of incompatible sizes would occur.
 
104
 
 
105
What happens in the current version is that resizing $a raises
 
106
a flag in $c: "PDL_PARENTDIMSCHANGED" and $b just raises the same flag
 
107
again. When $c is next evaluated, the flags are checked and it is found
 
108
that a recalculation is needed.
 
109
 
 
110
Of course, lazy evaluation can sometimes make debugging more painful
 
111
because errors may occur somewhere where you'd not expect them.
 
112
A better stack trace for errors is in the works for PDL, probably
 
113
so that you can toggle a switch $PDL::traceevals and get a good trace
 
114
of where the error actually was.
 
115
 
 
116
=head1 Families
 
117
 
 
118
This is one of the more intricate concepts of one-directional dataflow.
 
119
Consider the following code ($a and $b are pdls that have dataflow enabled):
 
120
 
 
121
        $c = $a + $b;
 
122
        $e = $c + 1;
 
123
        $d = $c->diagonal();
 
124
        $d ++;
 
125
        $f = $c + 1;
 
126
 
 
127
What should $e and $f contain now? What about when $a is changed
 
128
and a recalculation is triggered.
 
129
 
 
130
In order to make dataflow work like you'd expect, a rather strange
 
131
concept must be introduced: families. Let us make a diagram:
 
132
 
 
133
        a   b
 
134
         \ /
 
135
          c
 
136
         /|
 
137
        / |
 
138
       e  d
 
139
 
 
140
This is what PDL actually has in memory after the first three lines.
 
141
When $d is changed, we want $c to change but we don't want $e to change
 
142
because it already is on the graph. It may not be clear now why you don't
 
143
want it to change but if there were 40 lines of code between the 2nd
 
144
and 4th lines, you would. So we need to make a copy of $c and $d:
 
145
 
 
146
        a   b
 
147
         \ /
 
148
          c' . . . c
 
149
         /|        |\
 
150
        / |        | \
 
151
       e  d' . . . d  f
 
152
 
 
153
Notice that we primed the original c and d, because they do not correspond
 
154
to the objects in $c and $d any more. Also, notice the dotted lines
 
155
between the two objects: when $a is changed and this diagram is re-evaluated,
 
156
$c really does get the value of c' with the diagonal incremented.
 
157
 
 
158
To generalize on the above, whenever a piddle is mutated i.e.
 
159
when its actual *value* is forcibly changed (not just the reference:
 
160
 
 
161
        $d = $d + 1
 
162
 
 
163
would produce a completely different result ($c and $d would not be bound
 
164
any more whereas
 
165
 
 
166
        $d .= $d + 1
 
167
 
 
168
would yield the same as $d++), a "family" consisting of all other piddles
 
169
joined to the mutated piddle by a two-way transformation is created
 
170
and all those are copied.
 
171
 
 
172
All slices or transformations that simply select a subset of the original
 
173
pdl are two-way. Matrix inverse should be. No arithmetic
 
174
operators are.
 
175
 
 
176
=head1 Sources
 
177
 
 
178
What you were told in the previous section is not quite true:
 
179
the behaviour described is not *always* what you want. Sometimes you
 
180
would probably like to have a data "source":
 
181
 
 
182
        $a = pdl 2,3,4; $b = pdl 5,6,7;
 
183
        $c = $a + $b;
 
184
        line($c);
 
185
 
 
186
Now, if you know that $a is going to change and that you want
 
187
its children to change with it, you can declare it into a data source
 
188
(XXX unimplemented in current version):
 
189
 
 
190
        $a->datasource(1);
 
191
 
 
192
After this, $a++ or $a .= something will not create a new family
 
193
but will alter $a and cut its relation with its previous parents.
 
194
All its children will follow its current value.
 
195
 
 
196
So if $c in the previous section had been declared as a source,
 
197
$e and $f would remain equal.
 
198
 
 
199
=head1 Binding
 
200
 
 
201
A dataflow mechanism would not be very useful without the ability
 
202
to bind events onto changed data. Therefore, we provide such a mechanism:
 
203
 
 
204
        > $a = pdl 2,3,4
 
205
        > $b = $a + 1;
 
206
        > $c = $b * 2;
 
207
        > $c->bind( sub { print "A now: $a, C now: $c\n" } )
 
208
        > PDL::dowhenidle();
 
209
        A now: [2,3,4], C now: [6 8 10]
 
210
        > $a->set(0,1);
 
211
        > $a->set(1,1);
 
212
        > PDL::dowhenidle();
 
213
        A now: [1,1,4], C now: [4 4 10]
 
214
 
 
215
Notice how the callbacks only get called during PDL::dowhenidle.
 
216
An easy way to interface this to Perl event loop mechanisms
 
217
(such as Tk) is being planned.
 
218
 
 
219
There are many kinds of uses for this feature: self-updating graphs,
 
220
for instance.
 
221
 
 
222
Bla bla bla XXX more explanation
 
223
 
 
224
=head1 Limitations
 
225
 
 
226
Dataflow as such is a fairly limited addition on top of Perl.
 
227
To get a more refined addition, the internals of perl need to be
 
228
hacked a little. A true implementation would enable flow of everything,
 
229
including
 
230
 
 
231
=over 12
 
232
 
 
233
=item data
 
234
 
 
235
=item data size
 
236
 
 
237
=item datatype
 
238
 
 
239
=item operations
 
240
 
 
241
=back
 
242
 
 
243
At the moment we only have the first two (hey, 50% in a couple of months
 
244
is not bad ;) but even this is useful by itself. However, especially
 
245
the last one is desirable since it would add the possibility
 
246
of flowing closures from place to place and would make many things
 
247
more flexible.
 
248
 
 
249
To get the rest working, the internals of dataflow probably need to
 
250
be changed to be a more general framework.
 
251
 
 
252
Additionally, it would be nice to be able to flow data in time,
 
253
lucid-like (so you could easily define all kinds of signal processing
 
254
things).
 
255
 
 
256
=head1 AUTHOR
 
257
 
 
258
Copyright(C) 1997 Tuomas J. Lukka (lukka@fas.harvard.edu).
 
259
Redistribution in the same form is allowed provided that the copyright
 
260
notice stays intact but reprinting requires
 
261
a permission from the author.