Terrence - we talked about this at our latest NYCJUG meeting this past
Tuesday. Here's my initial write-up of our discussion. I hope you find it
helpful.
There has been a lot of discussion recently on the J Forum that indicates
difficulty people have understanding how J looks at multi-dimensional
arrays. Since this is one of the language's great strengths, and is
something most of us have not considered in a long time, it might pay to
re-visit how we think about this.
When I first learned these concepts in APL, I thought of zero-dimensional
arrays as corresponding to a geometric point; one-dimensional arrays are
like line segments; two-dimensional arrays are plane segments, and so on to
higher-dimensional arrays. For some reason though, in the recent
discussions, the conceptual problems seem to be with the smallest
dimensions, not the large ones as we might expect. However, I think this
confusion can be resolved by examining the ramifications of the following
insight.
One great insight of APL, and J, is that
the shape of any array is a vector of numbers.
This simple notion allows us to work with even high-dimensional arrays quite
easily because we don't have to grapple with how to visualize them
explicitly: we can look at only the vector of numbers representing the
array's dimensions. I'll shortly give an example of how this is helpful for
higher-dimensional arrays.
Sticking with this simple insight - the shape is a vector of numbers - makes
sense "all the way down":
A three-dimensional array's shape consists of three numbers.
A two-dimensional array's shape consists of two numbers.
A one-dimensional array's shape consists of one number.
A zero-dimensional array's shape consists of zero numbers.
The other sticking point, besides why scalars have the empty vector as their
shape, seems to be frames versus cells. Again, remembering only that the
shape is a vector, we can explain this dichotomy thusly: for a given shape
(vector of numbers), draw an imaginary (arbitrary) line between any two
numbers, separating the vector into two parts: the left portion is the
frame, the right one is the cells. For example, the shape of "i. 2 3 4 5"
can be divided like this
2 3 | 4 5
giving us a frame of shape "2 3" and cells of shape "4 5". The default
framing treats the leading axis specially, so this array, by default, would
be
2 | 3 4 5
that is, two items of shape "3 4 5".
That's all there is to it.
Everything else is "sound and fury, signifying nothing."
=== Easy 4-D Arrays ===
I've recently had occasion to work with four-dimensional arrays. One of the
things I've been doing is reducing a 4-D array on each of its dimensions in
turn. I never try to look at the whole array as it's awkward and difficult
to display neatly. Instead, I look only at its shape.
So, if my array has shape "20 30 80 25", I can sum the 20 3-D arrays by {{{
+/array}}}. To move the second coordinate "30" to the front, I use dyadic
transpose
{{{
$1 0 2 3|:array
30 20 80 25
}}}
again, looking only at the shape.
So I can sum the 30 3-D arrays by {{{+/1 0 2 3|:array}}}.
Similarly to move the third coordinate "80" to the front and sum, simply do
this {{{+/2 0 1 3|:array}}}.
By considering only the easily-displayable shape, I'm always certain I'm
working on the array the way I want to. I'm not disturbed by different
array displays that look the same because I seldom look directly at the
arrays.
Regards,
Devon
--
Devon McCormick, CFA
^me^ at acm.
org is my
preferred e-mail
----------------------------------------------------------------------
For information about J forums see http://www.jsoftware.com/forums.htm