[PYTHON MATRIX-SIG] First experiences

James Hugunin jjh@Goldilocks.LCS.MIT.EDU
Tue, 30 Jan 96 11:35:08 EST

   From: hinsenk@ere.umontreal.ca (Hinsen Konrad)

   Yesterday I replaced a rather awkward combination of a shell script
   and a Matlab program by a Python program that is shorter, easier to
   read, and faster than the old solution. First the most important and
   good news: it works, and it produces the same results as the Matlab

Great news!  This is of course one of the main purposes for this code.

   Of course I also noticed a few problems/strange features/possible
   improvements, and here they are for general discussion:

   "mrange" should be called "arange" now. Or maybe something clearer,
   e.g. "rangeArray"?

Definately "arange" (or something clearer but equally short).  I use
arange far to much to be willing to put up with a nice clear name like

   Why add.reduce(...) but outer(add, ...)? I have typed add.outer(...)
   more than once, and that makes more sense to me.

Writing outer product in python code was trivial, writing it in C
would have taken some time, so I cut some corners while I was still
unsure about the permanent status of pseudo-indices in the system.
I'll remove outer from the standard functions, and add a new method to
the ofuncs (ufuncs now?).

   There is a function sum() that is almost equivalent to add.reduce() -
   almost because it doesn't allow a second argument to specify the
   axis. Why?

I don't know whether or not sum even belongs in the set of standard
functions.  On the one hand I'd rather make people use add.reduce
because it's much more in the spirit of the array object.  On the
other hand, sum is such a friendly little function.  If it remains in
the system, then I agree it should get the second argument.

   The more I use it (and see it on my screen), the pseudo-index None
   seems strange to me. As a test, I have shown my code to a colleague
   who is an active Matlab user. I told him what x[2,3] means and asked
   him what he expects x[All, None] to mean. His immediate answer was:
   "everything along the first axis, nothing along the second axis." Then
   after a pause: "but that doesn't make sense."
   So once I again I propose to change the name to "NewAxis" or "New" or
   anything else indicating that this index *creates* a new dimension.

I agree with you here.  Clearly there is another naming issue to be
resolved.  See my next post.

   A related observation: I have used the combination [All, None] very
   often, but no other index expression involving All or None. This is of
   course a feature of my application, but I wouldn't be surprised if
   appending a new axis were the most frequent use of these
   pseudo-indices. In that case it would be worthwhile providing an
   equivalent convenience function that is shorter (i.e. less visually

Well, I find that All is used a lot of the time, but I agree with you
that None is almost always use to append a new axis.  I'll address
this also in my next post.

   Currently Numeric.py imports from fast_umath; in my opinion the
   default should be umath. Those who want speed can always overwrite the
   definition by importing from fast_umath.

And vice versa.  This is mainly a matter of personal taste, and since
my taste favors fast_umath, that's going to be the default version for
now.  If I find that many people on this sig disagree with me then
I'll change it.

   A minor cosmetic point: when I print a ufunc, is still says 'ofunc'.

That's because ufunc's are still called ofunc's.  This is another one
of those great renaming sorts of things, and it should be done.  

   Another cosmetic point: "Array.error" should be "ArrayError".

Easy to fix.

   I don't know how much effort this would be, but I'd really like
   reshape() to accept new shapes that lead to a different size. From my
   APL/J experience, I found that such reshaping is one of the most
   useful methods to construct non-standard matrices. Some examples:
   - an NxN array with all elements 37:
     reshape(37, (N, N))
   - a checkerboard matrix with 0s and 1s:
     reshape([1,0],(8,9))[All, 0..7]
   We could then eliminate special case constructors like zeros().

What you suggest would be very easy to code, but I don't want it
included in the behavior for reshape.  I like having reshape error
check my dimensions for me, and I like the fact that reshape doesn't
copy the whole array, but just returns a new pointer to it.

However, I have no objections to adding another method which does what
you're asking for.  What would you like it to be called?

   Another important function that seems to be missing is appending,
   i.e. the equivalent of + for lists. Of course for arrays it has
   to work along any axis.

Try this:

a = array([1,2,3])
a.concat([4,5], [7,8])
-> array([1,2,3,4,5,7,8])

I assume that this is what you're looking for?

It should probably work along any axis, but I don't have a terribly
good way to specify the axis and still keep the nice feature of being
able to concat together an arbitrary number of arrays (very important
for efficiency).  It would also be a bit of a hassle to write in C the
way you're suggesting, would it be enough to add in a standard python
function with the desired behavior?


MATRIX-SIG  - SIG on Matrix Math for Python

send messages to: matrix-sig@python.org
administrivia to: matrix-sig-request@python.org