🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: comp.lang.functional
2 messages
2 total messages Started by J. Michael Ashley Tue, 17 Jul 1990 16:28
re: Id array comprehensions revisited
#357
Author: J. Michael Ashley
Date: Tue, 17 Jul 1990 16:28
62 lines
3286 bytes
Wolfgand Grieskamp writes:
>In article <51123@iuvax.cs.indiana.edu> jashley@silver.ucs.indiana.edu (J. Michael Ashley) writes:
>>A little while ago I asked why array comprehensions are not parallel.  In
>>particular, why does an array comprehension like this:
>>
>>	{ array (1, n) | [i] = f i || i <- 1 to n }
>>
>not evaluate the (f i)'s concurrently?  Well, it turns out that the i's get
>generated sequentially as a list (a list in the data structure sense, mind
>you).
>
>This index list is intermediate and an optimizing compiler can eliminate it 
>using loop fusion.

[ omitting the pleasantly detailed derivation of optimization ]

>Using the above rule you get finaly:
>
>  DEF init1(A,f,i,n) == IF i>n  THEN A
>			IF i<=n THEN init1(update(A,i,f(i)),i+1,n) FI
>
>(A compiler will probably not use this fold/unfold method,
>because it depends to much on "eureka" steps. Furthermore, the view 
>is based on the assumption that update is O(1). Such an update
>can be established by a sharing analysis for the given example).
>
>Regarding to concurrent initialization assume simplisticaly that init1
>is not strict in its first argument.

Actually, this is precisely the optimization that the current Id compiler
does right now; if it sees the construct "1 to n", then the compiler will
transform it into a loop.

Since we are using I-structures, the update is O(1) (without sharing analysis),
and init1 is not strict in it's first argument.

This doesn't solve the problem, however.  Since we are using a dataflow
architecture, the function f will undergo partial evaluation to the point
where it must have it's argument.  What this means is that if we have lots
and lots of processors, 90% of the work of creating the array is done by
the first iteration or two of init1.  The execution is now bottlnecked by
this sequential generation of the indices.

A slightly better compiler will generate the indices in O(log n) time
without any trouble.

But this doesn't solve the problem completely.  In the case of 
accumulator comprehensions, the programmer will probably not be using this
easy-to-optimize "1 to n" construct.  Instead, there will be some arbitrary
function (probably complicated) that *must return a list*.  Even the most
trivial numerical codes will be more than a match for any compiler 
optimization.  So we are again stuck with lots of parallelism when 
generating the elements of the list but bounded by an O(n) append to put
this results back together to form the final list.

Thomas Breuel suggested a couple of ways ("difference lists and/or pointer
jumping") to overcome the O(n) append problem.  This is kind of a hack, and
Thomas admits that.  I still sit on the position that lists are not the
right data structure for the indices.

mike ashley
jashley@lanl.gov
Re: Id array comprehensions revisited
#355
Author: Wolfgang Grieskamp
Date: Tue, 17 Jul 1990 23:06
50 lines
2992 bytes
In article <51173@iuvax.cs.indiana.edu> jashley@silver.ucs.indiana.edu (J. Michael Ashley) writes:
>Wolfgang Grieskamp writes:
>
>>Using the above rule you get finaly:
>>
>>  DEF init1(A,f,i,n) == IF i>n  THEN A
>>			  IF i<=n THEN init1(update(A,i,f(i)),i+1,n) FI
>>
>> [...]

>>Regarding to concurrent initialization assume simplisticaly that init1
>>is [[not strict]] lazy in its first argument.
>
>
>This doesn't solve the problem, however.  Since we are using a dataflow
>architecture, the function f will undergo partial evaluation to the point
>where it must have it's argument.  

If I get it right, this a specific problem of dataflow architectures. init1
fires only, when *all* arguments are available, so the next recursion level
may only be reached when update(..) is available (must be something like 
this, I'am not so firm with dataflow architectures).

Anyway, array initialization is not only in FORTRAN inherently 
parallel, but also in functional languages, and that should be pointed out.
You might imagine the evaluation of init1 causes the creation of (n-i)+1 update
"processes". The result of update is not required to bound the recursion,
so init1 may terminate before any f(i) has been evaluated. The bottelneck
appears, if some f(i) is ready, and update requires the updated array of
the i+1 recursion level (this is a inherent problem (also in FORTRAN ...) 
you can only solve with some complicated analysis 
which ensures the commutativity of all performed updates).


>In the case of 
>accumulator comprehensions, the programmer will probably not be using this
>easy-to-optimize "1 to n" construct.  Instead, there will be some arbitrary
>function (probably complicated) that *must return a list*.  

Fusion in the case of the discussed array comprehensions works for *any* 
list producer with an arbitrary number of recursion and termination cases, not
only for "1 to n". However, the (conceptual) fold step can be only applied
to cases which have an outermost list constructor (so if you construct
the index list with a concatenate of two sublists, it will fail for this
case). Another problem is the compilers runtime ... so we actually need
parallel machines to write nice compilers!

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
			     Wolfgang Grieskamp 
wg@opal.cs.tu-berlin.de        tub!tubopal!wg         wg%opal@DB0TUI11.BITNET
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads