From dubois@kristen.llnl.gov  Wed Nov  1 02:56:19 1995
From: dubois@kristen.llnl.gov (P. Dubois)
Date: Wed, 1 Nov 1995 10:56:19 +0800
Subject: [PYTHON MATRIX-SIG] Some notes on the matrix class
Message-ID: <9511011856.AA29129@kristen.llnl.gov>

This is a very nice facility already and has an amazing amount of
functionality. What follows are some notes I made on it.
Other members of the MATRIX-SIG have probably played enough before with the
idea to realize what the examples don't show: the subscript notation
for multiple dimensions works perfectly...I'm stunned.

a. The already implemented list of functions/reduction operators is 
   impressive. We have also found useful:
   1. A function equal to max(m) - min(m), often used as a reduction operator
      in higher dimensions. We call it ptp (peak-to-peak). 

   2. ranf(m) fills m with uniform random numbers on (0.0, 1.0)

   3. A function reshape(x,n,m,...) equal to a copy of x reshaped as (n,m,...)
      The decision to make reshape a status-altering method is fine, but
      often the need for a reshape is in the context of some temporary 
      value needed in an expression. Some of the clever rank stuff 
      mitigates this need but I bet this still comes in very useful.
      Actually, our function of this kind also duplicates copies of
      x as needed provided length(x) divides the new size.

   4. The existing ones(n,m) will return a matrix of shape (n,m) 
      filled with 1.0; equally useful would be one where the i,j element is 
      1.0 iff i==j, 0.0 otherwise.

b. compress(condition, x) = those elements of x corresponding to those
   elements of condition that are "true". condition and x must have
   the same length (or x scalar), result is a one-dimensional vector with
   length equal to the number of true elements in condition. Naturally this 
   is most useful if x < y returns a vector instead of a scalar. 
   Most used form however is with a condition of the form x > 0. or some 
   similar comparison to a scalar, which are expressible already in Python 
   if we take "true" in this sense to be the normal Python meaning.

c. My Basis users love:
   where(condition,x,y) is shaped like condition and has elements of x and
   y where condition is respectively true or false; we allow broadcast of
   scalars x or y, so some thought about ranks should reveal the equivalent
   notion here. Often used in the form where(z, x/z, 1.e99); in this case
   we rely on a convention that something/0.0 = Infinity, where Infinity is
   some variable the users can set to suit them, but anyway the idea is that
   the computation x/z goes at compiled speed and does not cause an exception.
   We haven't found this perfect and of course would prefer that the 
   computation is simply not done at components where z is false. Given
   the genius you guys have already displayed ... (Yes, you can do this
   with a for loop, this is just a speed-freak need).

d. One curiosity is the notation something[(a,b,c)]. This is required
   because something[a,b,c] is a syntax error. But perhaps Python could
   allow the latter interpreted as the former. For if you do x=[1.,2.,3.]
   then trying x[(0,1,2)] produces a perfectly sensible error message.
   And it would be in the spirit of tuples not always needing the parentheses.
   (That sound you hear is the shot of a large caliber weapon as Guido 
   justifiably shoots a newbie for making a suggested language change before
   he can even use half the language yet; in fact, I'm tempted to shoot 
   myself, but I'm enjoying Python too much to die yet.)

 
   






=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From guido@CNRI.Reston.VA.US  Wed Nov  1 19:09:26 1995
From: guido@CNRI.Reston.VA.US (Guido van Rossum)
Date: Wed, 01 Nov 1995 14:09:26 -0500
Subject: [PYTHON MATRIX-SIG] Some notes on the matrix class
In-Reply-To: Your message of "Wed, 01 Nov 1995 10:56:19 +0800."
 <9511011856.AA29129@kristen.llnl.gov>
References: <9511011856.AA29129@kristen.llnl.gov>
Message-ID: <199511011909.OAA04346@monty>

> d. One curiosity is the notation something[(a,b,c)]. This is required
>    because something[a,b,c] is a syntax error. But perhaps Python could
>    allow the latter interpreted as the former. For if you do x=[1.,2.,3.]
>    then trying x[(0,1,2)] produces a perfectly sensible error message.
>    And it would be in the spirit of tuples not always needing the parentheses.
>    (That sound you hear is the shot of a large caliber weapon as Guido 
>    justifiably shoots a newbie for making a suggested language change before
>    he can even use half the language yet; in fact, I'm tempted to shoot 
>    myself, but I'm enjoying Python too much to die yet.)

Am I known to shoot newbies?  Only in my dreams :-)

This is actually a very reasonable request that has come up in this
context before.  It's a tad complicated to implement because there
some interference with the syntax for x[i:j], but should be possible.
If someone could contribute patches I'd be willing to review them and
add them to the next release; otherwise it may happen slower.  I
expect that changes are needed only to Grammar and compile.c...

--Guido van Rossum <guido@CNRI.Reston.VA.US>
URL: <http://www.python.org/~guido/>

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Wed Nov  1 20:28:58 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Wed,  1 Nov 95 15:28:58 -0500
Subject: [PYTHON MATRIX-SIG] Some notes on the matrix class
References: <9511011856.AA29129@kristen.llnl.gov>
Message-ID: <9511012028.AA00472@nineveh.lcs.mit.edu.LCS.MIT.EDU>


> Date: Wed, 1 Nov 1995 10:56:19 +0800
> From: "P. Dubois" <dubois@kristen.llnl.gov>
>
> This is a very nice facility already and has an amazing amount of
> functionality.

Thanks for the compliment and the feedback.

>    1. A function equal to max(m) - min(m), often used as a reduction operator
>       in higher dimensions. We call it ptp (peak-to-peak).

I'll add the following to the standard functions
def ptp(m): return max(m)-min(m)

where within Matrix.py, max(m) <--> maximum.reduce(m)

>    2. ranf(m) fills m with uniform random numbers on (0.0, 1.0)

I just added a function for this, (I needed to initialize a weight matrix  
for a NN) it has the form, m = rand(d1,...,dn).  where m will be a new  
matrix with the given dimensions.  It uses whrandom.py for getting its  
random numbers so is slow.  If somebody with a good random number generator  
in C would like to add this to matrixmodule.c as a new instantiation method  
in C, I'd use it.

>    3. A function reshape(x,n,m,...) equal to a copy of x reshaped as (n,m,...)

Already in my working copy of Matrix.py (requested by Konrad Hinsen).  I  
use the syntax reshape(x, (d1,...dn)) so that reshape(a, b.shape) works.  I  
don't like the idea of automatically making copies of the matrix in calls to  
reshape, but I have added the method m.copy(n=1) to make an arbitray number  
of copies of a matrix (this is much like the multiply operator for lists).   
(I also added a concat method noticing that I was missing this other  
functionality of lists).

>    4. The existing ones(n,m) will return a matrix of shape (n,m)
>       filled with 1.0; equally useful would be one where the i,j element is 
>       1.0 iff i==j, 0.0 otherwise.

This is now given by the eye(n,m,k=0) function (stolen from matlab), where  
the i,j element is 1.0 iff i-j==k, 0.0 otherwise.  This is easy enough to  
contruct yourself out of outer products (which is what eye does).

ie.
identity = equal.outer(mrange(n), mrange(m))

Aren't outer products cool?

> b. compress(condition, x) = those elements of x corresponding to those
>    elements of condition that are "true". condition and x must have
>    the same length (or x scalar), result is a one-dimensional vector with
>    length equal to the number of true elements in condition. Naturally this 
>    is most useful if x < y returns a vector instead of a scalar.
>    Most used form however is with a condition of the form x > 0. or some
>    similar comparison to a scalar, which are expressible already in Python 
>    if we take "true" in this sense to be the normal Python meaning.

This can be expressed as reshape(x, None)[condition.nonzero()].

My personal take on this is that if condition is not a vector, then this  
function is meaningless.  If it is a vector, it should be able to be applied  
to any dimension of x.

I'll add the following to Matrix.py to support this:

def compress(condition, m, dimension=-1):
	if dimension < 0: dimension = len(m.shape)+dimension
	if len(condition.shape)!=1 or len(condition)!=m.shape[dimension]:
 		raise ValueError
	index = [All]*len(m.shape)
	index[dimension] = condition.nonzero()
	print index
	return m[index]

BTW - while x < y returns a (meaningless) scalar, Matrix.less(x, y) returns  
a matrix of booleans.

There has been a small amount of talk about the possibilty of having  
"boolean types" in addition to number, sequence, and mapping types that  
would support >, <, ==, etc.  After writing a lot of code with matrices, I  
feel that many things could be expressed a lot more elegantly if this was  
allowed.  Unfortunately, Guido appears to be skeptical of this proposal, so  
don't hold your breath.

I've run into particular collisions with and, or, and not.  These functions  
when applied to matrices are renamed to the ugly "Matrix.andBoolean", etc.   
The problem is that the former are reserved words in python, so you can't  
create functions with those names (even in the "safe" context of a module).

> c. My Basis users love:
>    where(condition,x,y) is shaped like condition and has elements of x and
>    y where condition is respectively true or false; we allow broadcast of
>    scalars x or y, so some thought about ranks should reveal the equivalent
>    notion here. Often used in the form where(z, x/z, 1.e99); in this case
>    we rely on a convention that something/0.0 = Infinity, where Infinity is
>    some variable the users can set to suit them, but anyway the idea is that
>    the computation x/z goes at compiled speed and does not cause an exception.

I had something like this in my original matrix proposal, but was advised  
that it could be expressed as without any extra C-code:

def where(condition, x, y):
	c = notEqual(condition, 0)
	return c*x+(1-c)*y

where the I am relying on the fact that all comparision operators return 1  
for true.

This is in fact about 1/5th the speed of writing a where function in C, so  
it should be dropped to compiled code at some time.  I'll add this to the  
standard set of functions in Matrix.py.

>    We haven't found this perfect and of course would prefer that the
>    computation is simply not done at components where z is false. Given
>    the genius you guys have already displayed ... (Yes, you can do this
>    with a for loop, this is just a speed-freak need).

I'm a speed freak too, if you ever have to use a for loop to iterate over  
the contents of a matrix, feel free to report it as a bug in the matrix  
package.
--
You raise another interesting issue here that I've completely ignored in  
the matrix object so far.  Numeric exceptions are not handled at all; in  
return, matrix math executes at the speed of compiled code.  However, it  
wouldn't be too hard to add functions like safeDivide to the ofunc  
collection that would signal exceptions if someone considers this important.

I don't even have the hack that x/0.0 = some user settable Infinity.  x/0.0  
is set to the IEEE value for Infinity.

> d. One curiosity is the notation something[(a,b,c)]. This is required
>    because something[a,b,c] is a syntax error. But perhaps Python could
>    allow the latter interpreted as the former.

Guido beat me to this one.  I'd like to add that if anybody decides to go  
rummaging around in Grammer and compile.c, Guido also mentioned that he'd be  
willing to let a**b <--> pow(a, b) into the syntax.  This also seems like  
an easy hack for someone with the right know-how, and would be a nice bonus  
for numerical code.

There have been so many things added to the matrix object this week, that  
it seems I should get a new version out to those interested testers (so you  
won't need to ask me for features that are already there).  I'll put out a  
new object on Friday (if all goes well).  It will have all of the above  
additions (and many more), slightly different syntax for specifying the rank  
of an operator, working complex numbers, possibly working generic Python  
Objects as matrix elements and almost all of the memory leaks that I  
identified as clearly belonging to my code squashed (thanks to Purify).   
There are still a few memory leaks that appear to be in the python  
internals, and not due to my code (I think).  I'll check those out when I  
have more time.

-Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From guido@CNRI.Reston.VA.US  Wed Nov  1 20:31:19 1995
From: guido@CNRI.Reston.VA.US (Guido van Rossum)
Date: Wed, 01 Nov 1995 15:31:19 -0500
Subject: [PYTHON MATRIX-SIG] Some notes on the matrix class
In-Reply-To: Your message of "Wed, 01 Nov 1995 15:28:58 EST."
 <9511012028.AA00472@nineveh.lcs.mit.edu.LCS.MIT.EDU>
References: <9511011856.AA29129@kristen.llnl.gov>  <9511012028.AA00472@nineveh.lcs.mit.edu.LCS.MIT.EDU>
Message-ID: <199511012031.PAA04571@monty>

> There has been a small amount of talk about the possibilty of having  
> "boolean types" in addition to number, sequence, and mapping types that  
> would support >, <, ==, etc.  After writing a lot of code with matrices, I  
> feel that many things could be expressed a lot more elegantly if this was  
> allowed.  Unfortunately, Guido appears to be skeptical of this proposal, so  
> don't hold your breath.

Couldn't this be done by implementing a "numeric" type (at the C
level) that has a range of [0..1]?  It could have two objects...

Also, what exactly is the advantage of having a Boolean type?  (Am I
showing my age here? :-)

Re a**b for pow(a, b): yes, that's also an acceptable addition.

--Guido van Rossum <guido@CNRI.Reston.VA.US>
URL: <http://www.python.org/~guido/>

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Wed Nov  1 21:02:31 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Wed,  1 Nov 95 16:02:31 -0500
Subject: [PYTHON MATRIX-SIG] Some notes on the matrix class
References: <9511011856.AA29129@kristen.llnl.gov>
 <9511012028.AA00472@nineveh.lcs.mit.edu.LCS.MIT.EDU>
 <199511012031.PAA04571@monty>
Message-ID: <9511012102.AA00485@nineveh.lcs.mit.edu.LCS.MIT.EDU>


> Couldn't this be done by implementing a "numeric" type (at the C
> level) that has a range of [0..1]?  It could have two objects...
>
> Also, what exactly is the advantage of having a Boolean type?  (Am I
> showing my age here? :-)

What I'm asking for is to be able to create a new python object in C, and  
to include boolean methods for that object.  So, just like I can implement  
my matrix_add function for the syntax "a+b" when a and b are matrices  
(modulo coercion), I'd really like to be able to implement a matrix_greater  
function for the syntax "a>b" when a and b are matrices (still modulo  
coercion).  This seems completely in the original spirit of the language.

The reason for this is that if a = [1,2,3], and b = [2,2,2], I'd like to  
define a>b = [0,0,1].  (where all of the above are matrices).  This is  
useful in an astounding range of matrix computations, and there is no  
sensible definition of a>b for matrices that returns a scalar boolean value.  


ie. the traditional discrete delta function is elegantly expressed as
def delta(i): return i==0

delta([-2,-1,0,1,2,3,4]) -> [0,0,1,0,0,0,0]

It's also useful for "vectorizing" traditional operations like filter.  If  
x is a vector,

filter(lambda x: x<2 and x>0, x) <--> x.filter(x<2 and x>0)

except the second is orders of magnitude faster for matrices.

I understand that this is a major change to some of the more complicated  
parts of python, so there are good practical reasons that it won't be done  
anytime soon.  Nevertheless, I would love though to have you agree that this  
would be a good feature if somebody ever has the time to add it.

-Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From guido@CNRI.Reston.VA.US  Wed Nov  1 21:08:06 1995
From: guido@CNRI.Reston.VA.US (Guido van Rossum)
Date: Wed, 01 Nov 1995 16:08:06 -0500
Subject: [PYTHON MATRIX-SIG] Some notes on the matrix class
In-Reply-To: Your message of "Wed, 01 Nov 1995 16:02:31 EST."
 <9511012102.AA00485@nineveh.lcs.mit.edu.LCS.MIT.EDU>
References: <9511011856.AA29129@kristen.llnl.gov> <9511012028.AA00472@nineveh.lcs.mit.edu.LCS.MIT.EDU> <199511012031.PAA04571@monty>  <9511012102.AA00485@nineveh.lcs.mit.edu.LCS.MIT.EDU>
Message-ID: <199511012108.QAA06690@monty>

> The reason for this is that if a = [1,2,3], and b = [2,2,2], I'd
> like to define a>b = [0,0,1].  (where all of the above are
> matrices).  This is useful in an astounding range of matrix
> computations, and there is no sensible definition of a>b for
> matrices that returns a scalar boolean value.

I see that I misunderstood your question.  I'm not sure I like
subsuming the ">" operator (and its companions "<", "<=" etc.) for
this purpose.  In Python it's quite common (well, at least it's
possible) to use comparisons between objects of unknown type.  If I
write

	def spam(a, b):
		if a < b: ...do something...
		else: ...do something else...

and a and b can be anything.  If for certain types a<b returns a list
(which is always true) this could mess up some invariants that the
code relies on (e.g. exactly one of a<b, a==b, a>b is true).

Currently, it is not possible for comparisons to raise exceptions.
This may change in the future, however, and then matrices (like
complex numbers) should raise some exception to indicate that
comparing them doesn't make.

There is also the comparison chaining (a<b<c) which is implemented at
a rather low level in the language, and again assumes that a<b returns
true or false.

You can always define methods equal, greater and less, where
a.greater(b) = [0,0,1] in your example.

--Guido van Rossum <guido@CNRI.Reston.VA.US>
URL: <http://www.python.org/~guido/>

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jfulton@usgs.gov  Wed Nov  1 21:54:58 1995
From: jfulton@usgs.gov (Jim Fulton, U.S. Geological Survey)
Date: Wed, 01 Nov 1995 16:54:58 -0500
Subject: [PYTHON MATRIX-SIG] Some notes on the matrix class
In-Reply-To: <9511012102.AA00485@nineveh.lcs.mit.edu.LCS.MIT.EDU>
Message-ID: <199511012149.VAA04206@qvarsx.er.usgs.GOV>


On Wed, 1 Nov 95 16:02:31 -0500 
James Hugunin said:
> 
> > Couldn't this be done by implementing a "numeric" type (at the C
> > level) that has a range of [0..1]?  It could have two objects...
> >
> > Also, what exactly is the advantage of having a Boolean type?  (Am I
> > showing my age here? :-)
> 
> What I'm asking for is to be able to create a new python object in C, and  
> to include boolean methods for that object.  So, just like I can implement  
> my matrix_add function for the syntax "a+b" when a and b are matrices  
> (modulo coercion), I'd really like to be able to implement a matrix_greater  
> function for the syntax "a>b" when a and b are matrices (still modulo  
> coercion).  This seems completely in the original spirit of the language.
> 
> The reason for this is that if a = [1,2,3], and b = [2,2,2], I'd like to  
> define a>b = [0,0,1].  (where all of the above are matrices).  This is  
> useful in an astounding range of matrix computations, and there is no  
> sensible definition of a>b for matrices that returns a scalar boolean value.  
> 
> 
> ie. the traditional discrete delta function is elegantly expressed as
> def delta(i): return i==0
> 
> delta([-2,-1,0,1,2,3,4]) -> [0,0,1,0,0,0,0]
> 
> It's also useful for "vectorizing" traditional operations like filter.  If  
> x is a vector,
> 
> filter(lambda x: x<2 and x>0, x) <--> x.filter(x<2 and x>0)
> 
> except the second is orders of magnitude faster for matrices.
> 
> I understand that this is a major change to some of the more complicated  
> parts of python, so there are good practical reasons that it won't be done  
> anytime soon.  Nevertheless, I would love though to have you agree that this  
> would be a good feature if somebody ever has the time to add it.

I think what you want to do is best done with a separate function.

I'm against having comparison operators return non-boolean values.
I think comparison operators should always either return boolean, or
raise an exception if an operation is not supported.

With your proposal, would [1,2,3]==[0,2,3] return [0,1,1]?  Then you
would lose the ability to say: "if a == b:"

I'd much rather be able to say a particular type supports == and !=
and does not support <, <=, >, and >=.

Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Thu Nov  2 14:33:16 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Thu, 2 Nov 1995 09:33:16 -0500
Subject: [PYTHON MATRIX-SIG] Who wants to test my complex number module?
Message-ID: <199511021433.JAA13755@cyclone.ERE.UMontreal.CA>

This does not directly relate to matrices, but I suppose that most of
use are also interested in other numerical applications of Python.

I have written a C module that implements complex numbers, including
the standard arithmetic function, and another C module that is the
analogue of math for complex numbers.  Before releasing these to a
larger public, I'd like some others to test them for a while. Any
volunteers? The modules work with 1.2 as well as 1.3.

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Thu Nov  2 14:46:55 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Thu, 2 Nov 1995 09:46:55 -0500
Subject: [PYTHON MATRIX-SIG] Some notes on the matrix class
In-Reply-To: <9511011856.AA29129@kristen.llnl.gov> (dubois@kristen.llnl.gov)
Message-ID: <199511021446.JAA14200@cyclone.ERE.UMontreal.CA>


      2. ranf(m) fills m with uniform random numbers on (0.0, 1.0)

I'd prefer a matrix constructor (similar to mrange) that creates
a random matrix with a given shape.

   b. compress(condition, x) = those elements of x corresponding to those
      elements of condition that are "true". condition and x must have

A useful generalization of this, especially since booleans are just
integers in Python, would be a function that replicates each item of x
n times, where n is the corresponding item in the "condition"
argument.

      the same length (or x scalar), result is a one-dimensional vector with
      length equal to the number of true elements in condition. Naturally this 

Why should this be restricted to one-dimensional arguments? Of course
the "condition" argument must be one-dimensional, but the compression
(or copying, in the sense outlined above) can occur along any axis
of a multidimensional array.

      is most useful if x < y returns a vector instead of a scalar. 

Indeed...

   c. My Basis users love:
      where(condition,x,y) is shaped like condition and has elements of x and
      y where condition is respectively true or false; we allow broadcast of

If Python had a selection operator similar to C's ?:, this would be
its generalization to array arguments. And in fact I'd love to have
such an operator in Python in general...

      (That sound you hear is the shot of a large caliber weapon as Guido 
      justifiably shoots a newbie for making a suggested language change before
      he can even use half the language yet; in fact, I'm tempted to shoot 
      myself, but I'm enjoying Python too much to die yet.)

It would be more in the spirit of Python to use poisonous snakes instead
of guns ;-)


-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Thu Nov  2 15:10:08 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Thu, 2 Nov 1995 10:10:08 -0500
Subject: [PYTHON MATRIX-SIG] Some notes on the matrix class
In-Reply-To: <9511012028.AA00472@nineveh.lcs.mit.edu.LCS.MIT.EDU> (message from James Hugunin on Wed,  1 Nov 95 15:28:58 -0500)
Message-ID: <199511021510.KAA15138@cyclone.ERE.UMontreal.CA>


   random numbers so is slow.  If somebody with a good random number generator  
   in C would like to add this to matrixmodule.c as a new instantiation method  
   in C, I'd use it.

There is no shortage of random number generators in C, although I can't
find one right now on my disk...

   (I also added a concat method noticing that I was missing this other  
   functionality of lists).

Good. I was just about to ask for it...

   There has been a small amount of talk about the possibilty of having  
   "boolean types" in addition to number, sequence, and mapping types that  

I don't see the advantage in a language like Python. In a type-checked
compiled language, a boolean type makes sense, but in Python integers
are just as good and even more useful since you can use the results
of logical operations in arithmetic expressions.

On the other hand, I agree it would be nice (*very* nice) to be able
to define comparison operators that return matrix objects...

   You raise another interesting issue here that I've completely ignored in  
   the matrix object so far.  Numeric exceptions are not handled at all; in  
   return, matrix math executes at the speed of compiled code.  However, it  

I must say that I am not entirely happy with the fact tht Python uses
exceptions for floating point operations at all. In terms of speed and
versatility, I prefer to have IEEE-style operations that simply return
NaN or one of the infinities as the result of an "impossible"
operation. Of course there should be functions to check for these
special results. Such a strategy would be easily generalizable to
matrices, and on systems with IEEE implementations in hardware
(practically all computers on the market now) it would not cause
any speed penalty.

   rummaging around in Grammer and compile.c, Guido also mentioned that he'd be  
   willing to let a**b <--> pow(a, b) into the syntax.  This also seems like  
   an easy hack for someone with the right know-how, and would be a nice bonus  
   for numerical code.

I'd love that. And once we are discussing syntax, I'd also love to have
a concise input notation for complex numbers...

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Thu Nov  2 15:27:10 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Thu, 2 Nov 1995 10:27:10 -0500
Subject: [PYTHON MATRIX-SIG] Some notes on the matrix class
In-Reply-To: <199511012108.QAA06690@monty> (message from Guido van Rossum on Wed, 01 Nov 1995 16:08:06 -0500)
Message-ID: <199511021527.KAA15740@cyclone.ERE.UMontreal.CA>


   You can always define methods equal, greater and less, where
   a.greater(b) = [0,0,1] in your example.

But more complicated logical expressions with such a syntax become
impossible to read. In fact, I'd rather write a comparison using
map() and a lambda form if it weren't so inefficient.

The current state of comparisons in Python is extremely dangerous,
because comparisons always succeed even if they don't make any
sense. The worst consequence is that max() and min() always return a
result of the expected type, but which is usually not what the user
thinks it is. A perfect source for hard-to-find user errors. Of course
that could be fixed by just disallowing comparisons of non-comparable
objects, which however still does not solve the matrix comparison
problem.

Just an unfinished idea: would it be possible to construct a "matrix
expression evaluator" similar in syntax to map(), but efficient?

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From friedric@rose.rsoc.rockwell.com  Thu Nov  2 16:14:05 1995
From: friedric@rose.rsoc.rockwell.com (Robin Friedrich)
Date: Thu, 2 Nov 1995 10:14:05 -0600
Subject: [PYTHON MATRIX-SIG] Some notes on the matrix class
Message-ID: <9511021614.AA23987@darwin.rsoc.rockwell.com>

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

|> It would be more in the spirit of Python to use poisonous snakes instead
|> of guns ;-)

A 16-ton weight actually.



(sorry for the noise but this list has way too much signal!) 
keep up the good work.


=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From dubois@kristen.llnl.gov  Thu Nov  2 01:57:44 1995
From: dubois@kristen.llnl.gov (P. Dubois)
Date: Thu, 2 Nov 1995 09:57:44 +0800
Subject: [PYTHON MATRIX-SIG] floating point handling
In-Reply-To: <199511021510.KAA15138@cyclone.ERE.UMontreal.CA>
 (hinsenk@ere.umontreal.ca)
Message-ID: <9511021757.AA03825@kristen.llnl.gov>


(1) I disagree with Konrad's remarks on floating point.

I know of no production code that allows the generation of NaNs or any
of the other IEEE nonsense. If such a thing occurs in one of our codes 
it is an error and we need to hear about it immediately. Knowing *where*
the problem first occurred is crucial.

We use whatever facilities are provided on a given platform (and sometimes
there aren't any) to make sure that:

a. Any floating point problems signal FPE (which we then catch), except:
b. Fast-underflow-to-zero is turned on (Can make a real speed difference:
   if you don't do something about it, underflows result in system calls.)

There is no standardization in this area.

(2) I will supply a module that is equivalent to the Cray random number
generator. Stand by.




=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From P.S.Craig@durham.ac.uk  Fri Nov  3 09:38:16 1995
From: P.S.Craig@durham.ac.uk (P.S.Craig@durham.ac.uk)
Date: Fri, 3 Nov 1995 09:38:16 +0000 (GMT)
Subject: [PYTHON MATRIX-SIG] floating point handling
In-Reply-To: <9511021757.AA03825@kristen.llnl.gov> from "P. Dubois" at Nov 2, 95 09:57:44 am
Message-ID: <26057.9511030939@markov>

P. Dubois writes:
> 
> 
> (1) I disagree with Konrad's remarks on floating point.
> 
> I know of no production code that allows the generation of NaNs or any
> of the other IEEE nonsense. If such a thing occurs in one of our codes 
> it is an error and we need to hear about it immediately. Knowing *where*
> the problem first occurred is crucial.
> 

This is getting a bit silly. Whether the IEEE `nonsense' is
appropriate or not is context dependent. I make heavy use of S-Plus (a
statistics package with some APL like matrix addressing) and Matlab (a
widely used matrix arithmetic package with many practical
applications). Both of these return Inf for 1/0 and Nan for 0/0 and I
don't think they have to generate exceptions to do it.

It seems quite sensible to me that python should allow both modes of
operation, i.e. IEEE extended arithmetic or exceptions. And if that
means significant changes to the base language, I have to apologise to
Guido for creating work. The problem for me is that python is a much
better programming language than S-Plus or Matlab but that I need this
matrix/tensor class to be as like them as possible before I switch to
using it instead of them for my research.

Cheers,

Peter Craig




=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From guido@CNRI.Reston.VA.US  Fri Nov  3 13:20:58 1995
From: guido@CNRI.Reston.VA.US (Guido van Rossum)
Date: Fri, 03 Nov 1995 08:20:58 -0500
Subject: [PYTHON MATRIX-SIG] floating point handling
In-Reply-To: Your message of "Fri, 03 Nov 1995 09:38:16 GMT."
 <26057.9511030939@markov>
References: <26057.9511030939@markov>
Message-ID: <199511031320.IAA16812@monty>

> It seems quite sensible to me that python should allow both modes of
> operation, i.e. IEEE extended arithmetic or exceptions. And if that
> means significant changes to the base language, I have to apologise to
> Guido for creating work. The problem for me is that python is a much
> better programming language than S-Plus or Matlab but that I need this
> matrix/tensor class to be as like them as possible before I switch to
> using it instead of them for my research.

If you insist on having "Inf" for infinity and "NaN" for 1/0, all you
probably need to do is hack the floatobject.c module a wee bit, to
include representations for them and to return them in appropriate
cases.  I don't mind work but I have about 1,000,000 different
projects to attend to (two of them are due today :-) and things go
faster if people contribute patches instead of requesating changes.

(Not that a contributed patch will automatically end up in the
language -- that depends on the quality of the code and how well your
feel for what's "right" in Python agrees with mine...)

--Guido van Rossum <guido@CNRI.Reston.VA.US>
URL: <http://www.python.org/~guido/>

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Fri Nov  3 14:59:13 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 3 Nov 1995 09:59:13 -0500
Subject: [PYTHON MATRIX-SIG] floating point handling
In-Reply-To: <199511031320.IAA16812@monty> (message from Guido van Rossum on Fri, 03 Nov 1995 08:20:58 -0500)
Message-ID: <199511031459.JAA18261@cyclone.ERE.UMontreal.CA>


   If you insist on having "Inf" for infinity and "NaN" for 1/0, all you
   probably need to do is hack the floatobject.c module a wee bit, to
   include representations for them and to return them in appropriate

Indeed I don't think this is much work, having looked at the float
implementation quite a bit before writing the complex module. But
obviously there must be a way to enable or disable floating point
exceptions (I thing everyone agrees they are useful). I am not quite
sure what the appropriate way to do that would be - a variable in the
sys module would be nice, but probably expensive to check after each
float operation. A function with a boolean argument that sets a C
variable might be better. Or maybe there is a better way that I just
can't think of... The same flag could then be used in the complex and
matrix modules.

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From guido@CNRI.Reston.VA.US  Fri Nov  3 15:08:39 1995
From: guido@CNRI.Reston.VA.US (Guido van Rossum)
Date: Fri, 03 Nov 1995 10:08:39 -0500
Subject: [PYTHON MATRIX-SIG] floating point handling
In-Reply-To: Your message of "Fri, 03 Nov 1995 09:59:13 EST."
 <199511031459.JAA18261@cyclone.ERE.UMontreal.CA>
References: <199511031459.JAA18261@cyclone.ERE.UMontreal.CA>
Message-ID: <199511031508.KAA17260@monty>

>    If you insist on having "Inf" for infinity and "NaN" for 1/0, all you
>    probably need to do is hack the floatobject.c module a wee bit, to
>    include representations for them and to return them in appropriate
> 
> Indeed I don't think this is much work, having looked at the float
> implementation quite a bit before writing the complex module. But
> obviously there must be a way to enable or disable floating point
> exceptions (I thing everyone agrees they are useful). I am not quite
> sure what the appropriate way to do that would be - a variable in the
> sys module would be nice, but probably expensive to check after each
> float operation. A function with a boolean argument that sets a C
> variable might be better. Or maybe there is a better way that I just
> can't think of... The same flag could then be used in the complex and
> matrix modules.

Hmm...  Globals that affect the behavior of low-level objects are
rarely a good idea.  For instance, some non-compute-intensive module
may be using floats and expecting exceptions -- it will break if it is
used in your program that turns off exceptions...

How about introducing a new type, say ieeefloat, with the desired
behavior?  Its casting behavior could easily be designed to force
mixed-mode arithmetic (between standard and ieee floats) to be done in
ieee mode.

--Guido van Rossum <guido@CNRI.Reston.VA.US>
URL: <http://www.python.org/~guido/>

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Fri Nov  3 15:37:02 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Fri,  3 Nov 95 10:37:02 -0500
Subject: [PYTHON MATRIX-SIG] IEEE exceptions, casting, matrix multiplies, and default types
References: <199511031459.JAA18261@cyclone.ERE.UMontreal.CA>
Message-ID: <9511031537.AA03746@nineveh.lcs.mit.edu.LCS.MIT.EDU>


I'd like to generalize this discussion a little bit.  I've noticed four  
areas where the easiest solution would be to add a user-settable global  
variable to indicate a "desired" mode, yet I agree with Guido that as a  
general rule this is an extremely bad idea.

1) 1/0. returns Inf or raises exception

[Note: Matrix_i creates a matrix of ints, Matrix_d creates one of doubles]
2) Matrix_i(1,2,3) * Matrix_d(1.,2.,3.) == Matrix_d(1.,4.,6.) or raises exception

3) a * b is element-wise or is linear algebra style multiply

4) add([1,2,3], [4,5,6]) == Matrix_?(5,7,9) where the question is what the  
? should be.

I'm busy this morning getting the 0.11 release of the matrixobject  
together, so I don't have time for much more comment, I just wanted to point  
out that this is a very general question (in particular when thinking about  
matrices), and if we're really lucky there might be a nice general purpose  
answer.

-Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Fri Nov  3 17:00:14 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 3 Nov 1995 12:00:14 -0500
Subject: [PYTHON MATRIX-SIG] floating point handling
In-Reply-To: <199511031508.KAA17260@monty> (message from Guido van Rossum on Fri, 03 Nov 1995 10:08:39 -0500)
Message-ID: <199511031700.MAA25356@cyclone.ERE.UMontreal.CA>


   Hmm...  Globals that affect the behavior of low-level objects are
   rarely a good idea.  For instance, some non-compute-intensive module
   may be using floats and expecting exceptions -- it will break if it is
   used in your program that turns off exceptions...

That's indeed a problem. In fact this is a well-known problem for
APL users, since APL has a range of global variables that affect
the meaning of all functions (i.e. the index origin can be set to
zero or one). The solution that APL offers is that these variables
can be made local and thereby changed for an individual function,
but that is far from an ideal solution.

   How about introducing a new type, say ieeefloat, with the desired
   behavior?  Its casting behavior could easily be designed to force
   mixed-mode arithmetic (between standard and ieee floats) to be done in
   ieee mode.

I am sure two float types would create quite a bit of confusion for
users, especially those who don't care about error handling and don't
even want to understand the difference. For example, there would have
to be two different input and output notations to make clear which
version is used.

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From dubois@kristen.llnl.gov  Fri Nov  3 01:42:46 1995
From: dubois@kristen.llnl.gov (P. Dubois)
Date: Fri, 3 Nov 1995 09:42:46 +0800
Subject: [PYTHON MATRIX-SIG] Who wants to test my complex number module?
In-Reply-To: <199511031505.KAA18617@cyclone.ERE.UMontreal.CA>
 (hinsenk@ERE.UMontreal.CA)
Message-ID: <9511031742.AA09062@kristen.llnl.gov>

(This is the middle of a conversation about the complex
 module that Hinsen has developed, but some issues I wanted to mention
 to everyone).

a. It is a surprising thing (to me) that while tan is in the Fortran standard,
   cot isn't. We put one in Basis because it drove us crazy.

b. The conjugation function in Fortran is called conjg, not conj.
   We probably should have a functional equivalent, too, conjg(c).
   Actually, the conjugate not really an attribute of the object,
   it is a transform, and so I'd rather see a method which conjugates
   the given object and a conjg(c) which returns copy(c).conjg().
  
c. However, that leads us to the whole discussion of naming. I think if 
   you read "Reusable Software" by Bertrand Meyer, and have some experience
   with constructing large scale reusable component libraries (which is
   what Python is generating on a frightening scale) it turns out that
   a consistent naming convention is very, very important. Some of the
   lessons the Eiffel community has learned are:

   1. Abbreviations should be avoided. Basically, if you don't abbreviate
      you can't forget which abbreviation to use. So in the immediate case,
      I would favor conjugate rather than conjg. This tends to be against
      the traditions in a rapid prototyping language but the components
      we are building aren't the rapid prototype they are elements of
      the reusable software library. (Although, you can make a case that
      conjg isn't an abbreviation, it is the Fortran name which everyone
      knows!)

   2. It is more important for the names to be consistent than traditional.
      For example, the size of an object like a list, stack, or queue is
      invariably called count, and the operation to place an element at
      a certain position is put. In stacks, put might more traditionally
      be called "push" and the top item "top" or "first" but an Eiffel user
      will know without looking that the top item is going to be called 
      "item", as is the current item in a list.

   Fortunately, Python's name scoping mitigates quite a bit of the worry
   about name clashes, but the problem of a user learning a large body of
   components is still there.

d. In the matrix class, one ought to worry about putting a name like
   "pp". Not only are some users going to accidentally call one of their
   variables pp, when you read it you haven't a clue what it is. 
   PrintMatrix ? (Unless, has pp become a standard Python abbreviation for
   PrettyPrint?)

e. About the printed representation of a complex: shouldn't it be 
   complex(1.0, 1.1) not 1j1.1 ? There are two components to this thought.
   One is that the two parts should be presented with equal precision.
   Second is that it might come in handy if the printed form was readable
   back into Python, and there seems to be some "tradition" of this sort
   of convention in Python components already. The Fortran representation
   for code literals is (1.0, 1.1) which is also suggestive.

f. Note to ourselves: the printing of large matrices needs to be more 
   orderly and labeled.

   An example follows from Basis. Note the control variable available to
   change the printing precision on a "class-wide" basis. 


kristen[51] basis
Basis    (basis, Version 951101)
Run at 09:20:46 on 11/03/95 on the sun4m    machine, suffix 8544x
Initializing Basis System
Basis 11.0
Initializing 3-D Surface Plotting Routine
Initializing 3-D Isosurface Plotting Routine
Initializing Device Package
EZD Graphics Devices 3.4 NCAR
Initializing EZCURVE/NCAR Graphics
EZN Graphics Interface Version 5.5
Initializing Singular Value Decomposition
Initializing Polynomial Fitting
Initializing PFB Interface
PFB 4.1
Basis> real x = ones(5, 20)
Basis> x
x                  shape: (5,20)
 row col =         1             2             3             4
 1:            1.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 2:            0.00000E+00   1.00000E+00   0.00000E+00   0.00000E+00
 3:            0.00000E+00   0.00000E+00   1.00000E+00   0.00000E+00
 4:            0.00000E+00   0.00000E+00   0.00000E+00   1.00000E+00
 5:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 row col =         5             6             7             8
 1:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 2:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 3:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 4:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 5:            1.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 row col =         9            10            11            12
 1:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 2:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 3:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 4:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 5:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 row col =        13            14            15            16
 1:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 2:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 3:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 4:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 5:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 row col =        17            18            19            20
 1:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 2:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 3:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 4:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
 5:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
Basis> [x, x+2.]
[x,x+2.]           shape: (5,20,2)
Number of dimensions: 3, lengths:      5    20     2
INDEX(row,col,1)
 row col =         1             2             3             4
 1:            1.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 2:            0.00000D+00   1.00000D+00   0.00000D+00   0.00000D+00
 3:            0.00000D+00   0.00000D+00   1.00000D+00   0.00000D+00
 4:            0.00000D+00   0.00000D+00   0.00000D+00   1.00000D+00
 5:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 row col =         5             6             7             8
 1:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 2:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 3:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 4:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 5:            1.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 row col =         9            10            11            12
 1:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 2:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 3:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 4:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 5:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 row col =        13            14            15            16
 1:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 2:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 3:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 4:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 5:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 row col =        17            18            19            20
 1:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 2:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 3:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 4:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
 5:            0.00000D+00   0.00000D+00   0.00000D+00   0.00000D+00
INDEX(row,col,2)
 row col =         1             2             3             4
 1:            3.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 2:            2.00000D+00   3.00000D+00   2.00000D+00   2.00000D+00
 3:            2.00000D+00   2.00000D+00   3.00000D+00   2.00000D+00
 4:            2.00000D+00   2.00000D+00   2.00000D+00   3.00000D+00
 5:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 row col =         5             6             7             8
 1:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 2:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 3:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 4:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 5:            3.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 row col =         9            10            11            12
 1:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 2:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 3:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 4:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 5:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 row col =        13            14            15            16
 1:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 2:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 3:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 4:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 5:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 row col =        17            18            19            20
 1:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 2:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 3:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 4:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
 5:            2.00000D+00   2.00000D+00   2.00000D+00   2.00000D+00
================================================
Basis> fuzz=14; x
x                  shape: (5,20)
 row col =              1                      2
 1:            1.00000000000000E+00   0.00000000000000E+00
 2:            0.00000000000000E+00   1.00000000000000E+00
 3:            0.00000000000000E+00   0.00000000000000E+00
 4:            0.00000000000000E+00   0.00000000000000E+00
 5:            0.00000000000000E+00   0.00000000000000E+00
 row col =              3                      4
 1:            0.00000000000000E+00   0.00000000000000E+00
 2:            0.00000000000000E+00   0.00000000000000E+00
 3:            1.00000000000000E+00   0.00000000000000E+00
 4:            0.00000000000000E+00   1.00000000000000E+00
 5:            0.00000000000000E+00   0.00000000000000E+00
 row col =              5                      6
 1:            0.00000000000000E+00   0.00000000000000E+00
 2:            0.00000000000000E+00   0.00000000000000E+00
 3:            0.00000000000000E+00   0.00000000000000E+00
 4:            0.00000000000000E+00   0.00000000000000E+00
 5:            1.00000000000000E+00   0.00000000000000E+00
 row col =              7                      8
 1:            0.00000000000000E+00   0.00000000000000E+00
 2:            0.00000000000000E+00   0.00000000000000E+00
 3:            0.00000000000000E+00   0.00000000000000E+00
 4:            0.00000000000000E+00   0.00000000000000E+00
 5:            0.00000000000000E+00   0.00000000000000E+00
 row col =              9                     10
 1:            0.00000000000000E+00   0.00000000000000E+00
 2:            0.00000000000000E+00   0.00000000000000E+00
 3:            0.00000000000000E+00   0.00000000000000E+00
 4:            0.00000000000000E+00   0.00000000000000E+00
 5:            0.00000000000000E+00   0.00000000000000E+00
 row col =             11                     12
 1:            0.00000000000000E+00   0.00000000000000E+00
 2:            0.00000000000000E+00   0.00000000000000E+00
 3:            0.00000000000000E+00   0.00000000000000E+00
 4:            0.00000000000000E+00   0.00000000000000E+00
 5:            0.00000000000000E+00   0.00000000000000E+00
 row col =             13                     14
 1:            0.00000000000000E+00   0.00000000000000E+00
 2:            0.00000000000000E+00   0.00000000000000E+00
 3:            0.00000000000000E+00   0.00000000000000E+00
 4:            0.00000000000000E+00   0.00000000000000E+00
 5:            0.00000000000000E+00   0.00000000000000E+00
 row col =             15                     16
 1:            0.00000000000000E+00   0.00000000000000E+00
 2:            0.00000000000000E+00   0.00000000000000E+00
 3:            0.00000000000000E+00   0.00000000000000E+00
 4:            0.00000000000000E+00   0.00000000000000E+00
 5:            0.00000000000000E+00   0.00000000000000E+00
 row col =             17                     18
 1:            0.00000000000000E+00   0.00000000000000E+00
 2:            0.00000000000000E+00   0.00000000000000E+00
 3:            0.00000000000000E+00   0.00000000000000E+00
 4:            0.00000000000000E+00   0.00000000000000E+00
 5:            0.00000000000000E+00   0.00000000000000E+00
 row col =             19                     20
 1:            0.00000000000000E+00   0.00000000000000E+00
 2:            0.00000000000000E+00   0.00000000000000E+00
 3:            0.00000000000000E+00   0.00000000000000E+00
 4:            0.00000000000000E+00   0.00000000000000E+00
 5:            0.00000000000000E+00   0.00000000000000E+00

"Compression" is also useful, can be turned off by user:
Basis> real x= [1.,2.,3] // ones(1000)
Basis> x
x                  shape: (1003)
    1:           1.00000000000000E+00   2.00000000000000E+00
    3:           3.00000000000000E+00   1.00000000000000E+00
    5:1000       1.00000000000000E+00   1.00000000000000E+00
 1001:           1.00000000000000E+00   1.00000000000000E+00
 1003:           1.00000000000000E+00
Basis> [x,x/2.]
[x,x/2.]           shape: (1003,2)
 row col =                    1                      2
    1:               1.00000000000000D+00   5.00000000000000D-01
    2:               2.00000000000000D+00   1.00000000000000D+00
    3:               3.00000000000000D+00   1.50000000000000D+00
    4:1003           1.00000000000000D+00   5.00000000000000D-01
Basis> 

















=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Fri Nov  3 18:07:04 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Fri,  3 Nov 95 13:07:04 -0500
Subject: [PYTHON MATRIX-SIG] Naming conventions
References: <9511031742.AA09062@kristen.llnl.gov>
Message-ID: <9511031807.AA08561@nineveh.lcs.mit.edu.LCS.MIT.EDU>


> a. It is a surprising thing (to me) that while tan is in the Fortran standard,
>    cot isn't. We put one in Basis because it drove us crazy.

I completely agree that we should expand upon the basic mathematical  
functions, not feeling limited by the current math.h C-library.

> c. However, that leads us to the whole discussion of naming. I think if
>    you read "Reusable Software" by Bertrand Meyer, and have some experience
>    with constructing large scale reusable component libraries (which is
>    what Python is generating on a frightening scale) it turns out that
>    a consistent naming convention is very, very important. Some of the
>    lessons the Eiffel community has learned are:
>
>    1. Abbreviations should be avoided. Basically, if you don't abbreviate
>       you can't forget which abbreviation to use. So in the immediate case,
>       I would favor conjugate rather than conjg. This tends to be against
>       the traditions in a rapid prototyping language but the components
>       we are building aren't the rapid prototype they are elements of
>       the reusable software library. (Although, you can make a case that
>       conjg isn't an abbreviation, it is the Fortran name which everyone
>       knows!)

As somebody who hates FORTRAN, I'd really like to argue strongly against  
assuming that everybody knows a FORTRAN name.  I'd like to second your  
motion for "conjugate".

I've been trying to follow exactly the convention that you mention for  
naming my basic ofuncs, thus I have "multiply", "divide", "leftShift",  
"andBoolean", "andLogical", and even things like "absolute", and "power"  
though I can see arguments for "pow" and "abs".

> e. About the printed representation of a complex: shouldn't it be
>    complex(1.0, 1.1) not 1j1.1 ? There are two components to this thought.
>    One is that the two parts should be presented with equal precision.
>    Second is that it might come in handy if the printed form was readable
>    back into Python, and there seems to be some "tradition" of this sort
>    of convention in Python components already. The Fortran representation
>    for code literals is (1.0, 1.1) which is also suggestive.

I believe that what's going on here is that Konrad is hoping that something  
like 1.0j1.0 (note the reasonable precision) will become acceptable as an  
input form to python for creating complex numbers.  I know that printing out  
a matrix that has a lot of complex(1.0, 1.0) entries is hideous, so I'm in  
favor of this idea.

> d. In the matrix class, one ought to worry about putting a name like
>    "pp". Not only are some users going to accidentally call one of their
>    variables pp, when you read it you haven't a clue what it is.
>    PrintMatrix ? (Unless, has pp become a standard Python abbreviation for
>    PrettyPrint?)
> f. Note to ourselves: the printing of large matrices needs to be more
>    orderly and labeled.

I agree, pp is hideous.  It was only a hack so that I could easily write  
sample code and have the matrices printed out looking half-way decent.  The  
whole issue of printing matrices needs to be addressed.  One part of this  
issue is the desire that the basic printed representation of an object  
should correspond to a command that could be used to recreate that object,  
on the other hand, the well-labeled format you show from BASIS is generally  
what a user wants to see.  I'm ambivalent on this issue.  If somebody gives  
me a good routine for printing a matrix I'd love to add it to my code.

-Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Fri Nov  3 18:54:51 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 3 Nov 1995 13:54:51 -0500
Subject: [PYTHON MATRIX-SIG] Who wants to test my complex number module?
In-Reply-To: <9511031742.AA09062@kristen.llnl.gov> (dubois@kristen.llnl.gov)
Message-ID: <199511031854.NAA02955@cyclone.ERE.UMontreal.CA>


   a. It is a surprising thing (to me) that while tan is in the Fortran standard,
      cot isn't. We put one in Basis because it drove us crazy.

I haven't ever had a pressing need for cot(), but since it costs
virtually nothing to add such simple functions, there is little
reason not to do so. I already added the inverse hyperbolic functions
to my cmath module, because it seemed silly not to have them.
I am perfectly willing to add more functions, also to the float
math module.

This leads to the question of what functions would be desirable. In
addition to the full set of angular functions, I'd like to see the
error function and the gamma function. Anything else?

   b. The conjugation function in Fortran is called conjg, not conj.
      We probably should have a functional equivalent, too, conjg(c).
      Actually, the conjugate not really an attribute of the object,
      it is a transform, and so I'd rather see a method which conjugates
      the given object and a conjg(c) which returns copy(c).conjg().

I had already expected that objection. In fact the only reason why I
implemented conjugation as an attribute (which indeed it should not
be) is that I didn't want to add functions to the complex module.  I
envisioned that maybe one day one could make complex numbers a
standard part of Python, like floats, with their proper input
notation, and then there would be no more complex module. It could be
put into cmath, but it doesn't really belong there. I am open to any
suggestion on where to put this function...

      1. Abbreviations should be avoided. Basically, if you don't abbreviate
	 you can't forget which abbreviation to use. So in the immediate case,

That is also the position of Mathematica, and it works well in
practice. The only "safe" abbreviations are those long established in
mathematical notation, like "sin" or "log". On the other hand, does
anyone really want SquareRoot()? Even Mathematica uses Sqrt[].  I
think one needs a certain (very small) set of accepted abbreviations.
The point is not just ease of typing, but also keeping moderately
complex expressions short enough to be legible.

	 the reusable software library. (Although, you can make a case that
	 conjg isn't an abbreviation, it is the Fortran name which everyone
	 knows!)

I'd rather not make the assumption that everyone knows Fortran! In fact,
I'd be happy if I could one day forget Fortran.

   e. About the printed representation of a complex: shouldn't it be 
      complex(1.0, 1.1) not 1j1.1 ? There are two components to this thought.

For my taste complex(1.0,1.1) is too long, especially in matrices.

      One is that the two parts should be presented with equal precision.

Why? I find 3.1415926j0 much nicer than 3.1415926j0.0000000 (and shorter
too).

      Second is that it might come in handy if the printed form was readable
      back into Python, and there seems to be some "tradition" of this sort

Of course. My hope is that the output notation I use (which by the way
is stolen from APL2 and J) could become the accepted input notation
one day.

      of convention in Python components already. The Fortran representation
      for code literals is (1.0, 1.1) which is also suggestive.

But it can never become an input notation, since (1.0, 1.1) is read
as a tuple in Python. Even for output only it would be confusing.

For flexible output, there should be some kind of formatting option,
as it exists for floating point numbers. But that can't be implemented
in a module, so it doesn't exist for now.

   f. Note to ourselves: the printing of large matrices needs to be more 
      orderly and labeled.

Definitely. Again APL is a good example to copy.

   Basis> real x = ones(5, 20)
   Basis> x
   x                  shape: (5,20)
    row col =         1             2             3             4
    1:            1.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
    2:            0.00000E+00   1.00000E+00   0.00000E+00   0.00000E+00
    3:            0.00000E+00   0.00000E+00   1.00000E+00   0.00000E+00
    4:            0.00000E+00   0.00000E+00   0.00000E+00   1.00000E+00
    5:            0.00000E+00   0.00000E+00   0.00000E+00   0.00000E+00
   ...

I am not sure I'd like this to be the default output format.
The labels are nice for big matrices, but for small matrices
I'd prefer just the elements. Also, I'd prefer non-exponential
notations as long as it is reasonable for all elements (as in
this case).

APL systems tend to choose the optimal output format based
on many properties of the matrix, and I have really come
to appreciate that. Unfortunately, J doesn't follow this
tradition.

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Fri Nov  3 19:02:33 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 3 Nov 1995 14:02:33 -0500
Subject: [PYTHON MATRIX-SIG] Naming conventions
In-Reply-To: <9511031807.AA08561@nineveh.lcs.mit.edu.LCS.MIT.EDU> (message from James Hugunin on Fri,  3 Nov 95 13:07:04 -0500)
Message-ID: <199511031902.OAA03346@cyclone.ERE.UMontreal.CA>


   whole issue of printing matrices needs to be addressed.  One part of this  
   issue is the desire that the basic printed representation of an object  
   should correspond to a command that could be used to recreate that object,  
   on the other hand, the well-labeled format you show from BASIS is generally  
   what a user wants to see.  I'm ambivalent on this issue.  If somebody gives  

Python has repr() and str(), so we can have both. My suggestion is
an input-like notation for repr(), and a human-readable one for str()
and therefore print. The fact is that for matrices it doesn't make
sense to use the same format for input and output. Matrix constants
will only be used for small matrices, and they must consist of
some linear arrangement. But much larger matrices will be generated
by other means, and they have to be printed in a readable way.

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From dubois@kristen.llnl.gov  Fri Nov  3 03:49:54 1995
From: dubois@kristen.llnl.gov (P. Dubois)
Date: Fri, 3 Nov 1995 11:49:54 +0800
Subject: [PYTHON MATRIX-SIG] printing complexes
Message-ID: <9511031949.AA13959@kristen.llnl.gov>

That was an excellent point you just made about str() and repr().
I think. I'm so new to Python I'm not sure which is which (:->

The reason I was worried about the precision being the same on the two sides
(and controllable) is simply the issue of making nice output where you
want things to line up for comparison. It is jarring if you have a list
and successive elements are all different in appearance, and it makes
it harder to make a nice table.

I didn't know about the J/APL2 convention, thanks for explaining it.

FYI, in Basis I don't have complex constants, just IMAGINARY ones. 
You do things like:

1i
1i       = (   0.00000D+00,   1.00000D+00)
Basis> 3 + 2.5i
3+2.5i   = (   3.00000D+00,   2.50000D+00)
Basis> 

As you see, I use the Fortran printing convention which is, of course,
unacceptable in Python.  But in array printing I don't, I use spacing:

iota(10) + 2i
iota(10)+2i        shape: (10)
  1:        1.00000D+00,  2.00000D+00    2.00000D+00,  2.00000D+00
  3:        3.00000D+00,  2.00000D+00    4.00000D+00,  2.00000D+00
  5:        5.00000D+00,  2.00000D+00    6.00000D+00,  2.00000D+00
  7:        7.00000D+00,  2.00000D+00    8.00000D+00,  2.00000D+00
  9:        9.00000D+00,  2.00000D+00    1.00000D+01,  2.00000D+00
Basis> 







=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Fri Nov  3 21:12:53 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 3 Nov 1995 16:12:53 -0500
Subject: [PYTHON MATRIX-SIG] printing complexes
In-Reply-To: <9511031949.AA13959@kristen.llnl.gov> (dubois@kristen.llnl.gov)
Message-ID: <199511032112.QAA10966@cyclone.ERE.UMontreal.CA>


   The reason I was worried about the precision being the same on the two sides
   (and controllable) is simply the issue of making nice output where you
   want things to line up for comparison. It is jarring if you have a list
   and successive elements are all different in appearance, and it makes
   it harder to make a nice table.

For matrices (and possibly sequence types in general) this is indeed
an issue. But what should be equal is not the precision of the real
and imaginary part of each number, but the real parts of all numbers
and the imaginary parts of all numbers.

My suggestion for formatting float and complex numbers in matrices
is the following:

Define an "order" of output formats as
1) integer
2) non-exponential floating point
3) exponential notation
Next, determine the appropriate format for each entry of the matrix,
using the same criterion as for %g-format in C to distinguish between
2 and 3. Then find the highest "order" used in the matrix (and the
widest output field if the order is 1 (integer)) and apply it to all
elements. For complex numbers, do this procedure independently for the
real and imaginary parts.

The result is a format in which all columns are lined up properly
and have equal widths, but which also is the most compact possible.

   FYI, in Basis I don't have complex constants, just IMAGINARY ones. 

That's an alternative I have considered, and if there is a general
preference for it, I am perfectly happy with it. But it should be used
equally for input and output. Still I prefer the APL2/J notation
because it can never give the impression of an arithmetic impression.
Consider printing an expression with complex constants and multiplications
in it. I am sure some people would read 2+3i * 1-7i as equivalent to
2-4i, so you'd have to print all complex numbers in parentheses (which
of course would also be obligatory for input).

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From dubois@kristen.llnl.gov  Fri Nov  3 05:25:07 1995
From: dubois@kristen.llnl.gov (P. Dubois)
Date: Fri, 3 Nov 1995 13:25:07 +0800
Subject: [PYTHON MATRIX-SIG] printing complexes
In-Reply-To: <199511032112.QAA10966@cyclone.ERE.UMontreal.CA>
 (hinsenk@ERE.UMontreal.CA)
Message-ID: <9511032125.AA16768@kristen.llnl.gov>

Actually, allow me to admit that the notation 3 + 4i in Basis *is*
arithmetic, so that indeed 2 + 3i * 1 - 7i is 2-4i. While I think I
know more about how to right a parser now, back in 1984 I didn't, so I
took this very lazy way of introducing complex numbers.

That said, it should be noted that the overwhelming percentage of all
our matrices and complex numbers are created by users accessing compiled
variables in common blocks that have been filled by compiled routines.
So actual occurrence of a complex literal AS INPUT is rare.
I think that would be true for most Python users too. You get complex
numbers by reading some data and doing an FFT or eigenproblem or calculating
some field, usually. So the question of how to represent complex literals
in Python input is probably not very important as long as you don't end up
screwing something up, like making the scanner twice as costly etc.



=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From dubois@kristen.llnl.gov  Fri Nov  3 05:37:46 1995
From: dubois@kristen.llnl.gov (P. Dubois)
Date: Fri, 3 Nov 1995 13:37:46 +0800
Subject: [PYTHON MATRIX-SIG] the imaginary constant idea is not good
Message-ID: <9511032137.AA17068@kristen.llnl.gov>

I think I'd better say that I didn't mean to suggest that the imaginary
constants idea in Basis was a good idea; it isn't. It made it easy on me
at the time, and as I said it has worked o.k. because it really isn't
used much.

Anybody know what is in Matlab or IDL?

Paul

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Fri Nov  3 21:44:41 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 3 Nov 1995 16:44:41 -0500
Subject: [PYTHON MATRIX-SIG] printing complexes
In-Reply-To: <9511032125.AA16768@kristen.llnl.gov> (dubois@kristen.llnl.gov)
Message-ID: <199511032144.QAA13884@cyclone.ERE.UMontreal.CA>


   know more about how to right a parser now, back in 1984 I didn't, so I
   took this very lazy way of introducing complex numbers.

It's not bad at all for input. I just don't think it is the best for
output. But it's certainly good enough.

   So actual occurrence of a complex literal AS INPUT is rare.

True enough...

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Fri Nov  3 22:03:30 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 3 Nov 1995 17:03:30 -0500
Subject: [PYTHON MATRIX-SIG] the imaginary constant idea is not good
In-Reply-To: <9511032137.AA17068@kristen.llnl.gov> (dubois@kristen.llnl.gov)
Message-ID: <199511032203.RAA15034@cyclone.ERE.UMontreal.CA>


   Anybody know what is in Matlab or IDL?

Matlab uses the same notation you chose for BASIS, for input and
output.

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From chris.chase@jhuapl.edu  Fri Nov  3 22:36:48 1995
From: chris.chase@jhuapl.edu (Chris Chase S1A)
Date: Fri, 3 Nov 1995 17:36:48 -0500
Subject: [PYTHON MATRIX-SIG] the imaginary constant idea is not good
In-Reply-To: <9511032137.AA17068@kristen.llnl.gov>
References: <9511032137.AA17068@kristen.llnl.gov>
Message-ID: <199511032233.RAA29802@python.org>


Paul> Anybody know what is in Matlab or IDL?

IDL uses a function: complex(real, imaginary).  Output is 
"(real, imaginary)" without the quotes.  Arrays of complex numbers are
easily formed by using arrays for the real and imaginary parts.

Matlab uses a complex constant i or j (actually functions) with the
special notation that allows affixing i or j to a numeric constant,
i.e. 2i = 2*i.  Thus, 2 + 3i * 1 - 7i is 2-4i.  Parentheses must be
used to obtain the other interpretation.  The use of i or j as
functions can be hidden by a local variable of the same name.  Output
uses the i suffix.

Chris

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Fri Nov  3 17:04:24 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 3 Nov 1995 12:04:24 -0500
Subject: [PYTHON MATRIX-SIG] IEEE exceptions, casting, matrix multiplies, and default types
In-Reply-To: <9511031537.AA03746@nineveh.lcs.mit.edu.LCS.MIT.EDU> (message from James Hugunin on Fri,  3 Nov 95 10:37:02 -0500)
Message-ID: <199511031704.MAA26533@cyclone.ERE.UMontreal.CA>


   [Note: Matrix_i creates a matrix of ints, Matrix_d creates one of doubles]
   2) Matrix_i(1,2,3) * Matrix_d(1.,2.,3.) == Matrix_d(1.,4.,6.) or raises exception

I see no reason why matrices should have different coercion rules (or
even none at all) than scalar numbers. So the result should be a
float matrix.

   4) add([1,2,3], [4,5,6]) == Matrix_?(5,7,9) where the question is what the  
   ? should be.

The rule should be that first the lists get transformed into matrices
of a certain type, and then addition proceeds using the normal coercion
rules. My suggestion for determining the global type of a list is that
it should be complex if at least one element is complex, else float
if at least one element is float, or otherwise integer.


That of course leaves two of your points as starting points for
extensive ideological fights ;-)

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From dubois@kristen.llnl.gov  Mon Nov  6 01:14:09 1995
From: dubois@kristen.llnl.gov (P. Dubois)
Date: Mon, 6 Nov 1995 09:14:09 +0800
Subject: [PYTHON MATRIX-SIG] casting and default types
In-Reply-To: <199511031704.MAA26533@cyclone.ERE.UMontreal.CA>
 (hinsenk@ere.umontreal.ca)
Message-ID: <9511061714.AA17004@kristen.llnl.gov>

I agree with Konrad's view: the type of the matrix to be created from
a list should be the least type conforming to all the components,
and the same should go for the result of an expression.

One could have the Matrix_? operators which strictly required the correct
kind of list as an argument, and just plain Matrix(list) would be the
creation routine which was "clever" at figuring this out.

In Basis, [1,2,3] is an integer array, [1,2,3.] is a real array.

Combined with the expression rule, this works well. I think no coercion
is probably workable but less desireable.

Related to this is what such "coercion" means for characters. If you
have a list [a,b,c] where a,b,c are all strings, Basis interprets the
"type" of the resulting matrix to be "strings of length max(len(a),len(b),
len(c)), and the component strings are copied into the new structure with
right blank fill to this new length.

(I keep mentioning Basis simply as a way of letting you all know what one way
is that users found acceptable; this is a set of semantics that has 10 years
of intensive user testing. When there is something the users didn't like
about it, I'll tell you that too. In this area, there are no complaints
whatsoever.)







=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From dubois@kristen.llnl.gov  Mon Nov  6 01:35:16 1995
From: dubois@kristen.llnl.gov (P. Dubois)
Date: Mon, 6 Nov 1995 09:35:16 +0800
Subject: [PYTHON MATRIX-SIG] A related idea
Message-ID: <9511061735.AA17513@kristen.llnl.gov>

Suppose we have the matrix class working. Suppose there is a Fortran
or C array in the program which you would like to "adopt" as a 
matrix in Python. The only difference between this and a matrix created a
normal way is that you have to remember never to free the memory.
So it seems you might be able to do this if you had a method
of creation (from C) which took a pointer,size,type kind of 
description. You could then increment the reference counter one extra, so
that the memory is never freed, or a "don't free" flag could be in the
header. 








=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Tue Nov  7 14:56:39 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Tue,  7 Nov 95 09:56:39 -0500
Subject: [PYTHON MATRIX-SIG] A related idea
References: <9511061735.AA17513@kristen.llnl.gov>
Message-ID: <9511071456.AA11707@nineveh.lcs.mit.edu.LCS.MIT.EDU>


> Suppose we have the matrix class working.

What do you mean suppose ;)  ?

> Suppose there is a Fortran
> or C array in the program which you would like to "adopt" as a
> matrix in Python. The only difference between this and a matrix created a
> normal way is that you have to remember never to free the memory.
> So it seems you might be able to do this if you had a method
> of creation (from C) which took a pointer,size,type kind of
> description. You could then increment the reference counter one extra, so
> that the memory is never freed, or a "don't free" flag could be in the
> header.

I agree that there should be a function to create a new matrix object from  
an existing array in C (or FORTRAN).  What we disagree about is the  
semantics.  I played around a while with the idea of "sharing" an array  
between python and C.  I found that as a general rule I ran into memory leak  
problems (or worse).  Using your scheme, python is never responsible for  
freeing the allocated memory, this means that the C code must be responsible  
for it, but the C code can't know when it is safe to free the memory  
because even when it's done with it there might still be a python reference  
to the memory.

Let me know if I'm completely missing something here, and this memory leak  
issue isn't really a problem.

I made the general decision to completely avoid these sorts of issues by  
(almost) never returning arrays that are references to other arrays.  I  
found that doing a malloc and a memcpy is usually sufficiently faster than  
any operation I'm going to perform on the array that it could be ignored.   
In order for this to be a valid assumption, I need to be working on a system  
where I have "more than enough" memory hanging around.  This is always true  
for me, but I'm interested in cases where it's not.

Note: the following will be completely meaningless to you if you haven't  
played with the alpha matrix object, so please ignore.

---

I'd add the following function to do what you're suggesting, but using my  
semantics (this is off the top of my head, so there're no guarantees it will  
work).

PyObject *PyMatrix_FromDimsAndData(int nd, int *dimensions, char type, void  
*data) {
	PyMatrixObject *ret = PyMatrix_FromDims(nd, dimensions, type);
	memcpy(ret->data, data, NBYTES(ret));
	return (PyObject *)ret;
}

I'll add something like this to the next release.

-Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Tue Nov  7 15:12:44 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Tue,  7 Nov 95 10:12:44 -0500
Subject: [PYTHON MATRIX-SIG] casting and default types
References: <9511061714.AA17004@kristen.llnl.gov>
Message-ID: <9511071512.AA11715@nineveh.lcs.mit.edu.LCS.MIT.EDU>


I've had a couple of discussions with Jim Fulton about exactly this issue  
when I first grabbed his matrix object.  If he's reading this, I would  
really like to get his opinion.

I agree with you, and for my uses full automatic coercion as well as  
reasonable choices for matrix type in instantiation is a good idea.

The current instantiation (and lack of coercion) system is Jim Fulton's  
(more or less) and he could do a much better job of defending it than me.   
The principle issue is that automatic type coercions can hide bugs.  The  
other issue is that automatic coercion can hide efficiency problems.  If I  
have a vector of ints that I'm frequently going to have to multiply by  
different vectors of floats, then it would be much more efficient for me to  
convert it to a vector of floats one time.  If I have automatic type  
coercion, I might never even notice this problem (except that my multiply  
operation would be something like a factor of two slower).

This is why I mentioned this issue as something that might be amenable to  
some sort of flag in the same way that IEEE exceptions could be (I was just  
noticing that a system of this sort is enabled on the DEC alpha's).  If I  
want to be really careful, I'd insist that adding floats to ints raised an  
exception, and simlarly that dividing by zero would do the same.  If I was  
willing to play fast and loose then I could disable these forms of "error  
checking" and I'd be off.

Still not sure what's the "right" way,
Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Tue Nov  7 19:43:37 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 7 Nov 1995 14:43:37 -0500
Subject: [PYTHON MATRIX-SIG] casting and default types
In-Reply-To: <9511071512.AA11715@nineveh.lcs.mit.edu.LCS.MIT.EDU> (message from James Hugunin on Tue,  7 Nov 95 10:12:44 -0500)
Message-ID: <199511071943.OAA23753@cyclone.ERE.UMontreal.CA>


   The current instantiation (and lack of coercion) system is Jim Fulton's  
   (more or less) and he could do a much better job of defending it than me.   
   The principle issue is that automatic type coercions can hide bugs.  The  

Whether or not coercion is a good idea is an old argument, but
for Python it has long been decided: Python has coercion, and
not having it for matrices would be simply inconsistent.

   other issue is that automatic coercion can hide efficiency problems.  If I  
   have a vector of ints that I'm frequently going to have to multiply by  
   different vectors of floats, then it would be much more efficient for me to  
   convert it to a vector of floats one time.  If I have automatic type  

I'd suppose that people who need the highest possible performance
are aware of this problem and are watching out for it. There
is a profiler for Python that can help find such problems. I don't
see this as a valid reason Python inconsistent and most users'
life more difficult.

   This is why I mentioned this issue as something that might be amenable to  
   some sort of flag in the same way that IEEE exceptions could be (I was just  

That's of course a possible solution, if someone thinks this
is really important.

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jfulton@usgs.gov  Tue Nov  7 20:46:35 1995
From: jfulton@usgs.gov (Jim Fulton, U.S. Geological Survey)
Date: Tue, 07 Nov 1995 15:46:35 -0500
Subject: [PYTHON MATRIX-SIG] casting and default types
In-Reply-To: <199511071943.OAA23753@cyclone.ERE.UMontreal.CA>
Message-ID: <199511072041.UAA21889@qvarsx.er.usgs.GOV>


First of all, I want to apologize for not participating in this list
much lately.  I've been buried in a project here and haven't had time
to keep up.

On Tue, 7 Nov 1995 14:43:37 -0500 
Hinsen Konrad said:
> 
>    The current instantiation (and lack of coercion) system is Jim Fulton's  
>    (more or less) and he could do a much better job of defending it than me.   
>    The principle issue is that automatic type coercions can hide bugs.  The  
> 
> Whether or not coercion is a good idea is an old argument, but
> for Python it has long been decided: Python has coercion, and
> not having it for matrices would be simply inconsistent.

Actually, this is not true.  There are some places where coersion
takes place automatically, but there are lot's of places where it
doesn't.  In the case of numbers, witness the float() and int()
functions.  Similarly, lists are not automatically converted to tuples
in many places where tuples are required.  And so on.
 
>    other issue is that automatic coercion can hide efficiency problems.  If I  
>    have a vector of ints that I'm frequently going to have to multiply by  
>    different vectors of floats, then it would be much more efficient for me to  
>    convert it to a vector of floats one time.  If I have automatic type  
> 
> I'd suppose that people who need the highest possible performance
> are aware of this problem and are watching out for it. There
> is a profiler for Python that can help find such problems. I don't
> see this as a valid reason Python inconsistent and most users'
> life more difficult.

It's not just a matter of performance.  It is also a matter of
correctness in some cases.  
 
>    This is why I mentioned this issue as something that might be amenable to  
>    some sort of flag in the same way that IEEE exceptions could be (I was just  
> 
> That's of course a possible solution, if someone thinks this
> is really important.

Global variables are evil.

I'd be much more in favor of having different kinds of matrices that
automagically coerce, if people really want this.

I have to bring myself up to date on the in's and outs of this coersion
issue.  I think my objection to Jim's original coersion proposal had to
do with ranks, more than the actual data types.  There are certainly
situations where coersion makes sense.  For example, in my Fortran
interface, FIDL, I automatically convert between argument and expected
numeric element types.

Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Tue Nov  7 21:02:56 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 7 Nov 1995 16:02:56 -0500
Subject: [PYTHON MATRIX-SIG] casting and default types
In-Reply-To: <199511072041.UAA21889@qvarsx.er.usgs.GOV> (jfulton@wrdmail.er.usgs.gov)
Message-ID: <199511072102.QAA29127@cyclone.ERE.UMontreal.CA>


   Actually, this is not true.  There are some places where coersion
   takes place automatically, but there are lot's of places where it
   doesn't.  In the case of numbers, witness the float() and int()
   functions.  Similarly, lists are not automatically converted to tuples

I can't imagine a need for float() and int() except in order to
"downgrade" a number. In all mathematical operations where floats
are required, I can just as well use ints. Lists and tuples are
another problem, of course.

My point of view is that as far as coercion is concerned, matrices
should behave just like scalars of the same type(s).

   It's not just a matter of performance.  It is also a matter of
   correctness in some cases.  

I don't understand. The choice is automatic coercion or none at all,
i.e. throwing an exception for mixed-type operations. I don't see
how one or the other can lead to a wrong result; it's either the
correct result or no result.

Of course there is some chance of making a mistake and not noticing
it due to automatic coercion, but then you already have the same
risk with scalars. Besides, I just can't think of a reasonable
example...

Also, I'd expect users to be familiar with coercion. I haven't
made a survey, but I'd claim that most languages have coercion
between numerical types, similar to Python. That's certainly
true for the languages most used for numerical work.

   I'd be much more in favor of having different kinds of matrices that
   automagically coerce, if people really want this.

Which creates some question and probably a lot of confusion.
What happens if coercing and non-coercing matrices are combined?
What happens if a function written for one type of matrices
is used with the other? How can the matrices be distinguished
in output?

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jfulton@usgs.gov  Wed Nov  8 14:01:11 1995
From: jfulton@usgs.gov (Jim Fulton, U.S. Geological Survey)
Date: Wed, 08 Nov 1995 09:01:11 -0500
Subject: [PYTHON MATRIX-SIG] casting and default types
In-Reply-To: <199511072102.QAA29127@cyclone.ERE.UMontreal.CA>
Message-ID: <199511081356.NAA14836@qvarsx.er.usgs.GOV>


On Tue, 7 Nov 1995 16:02:56 -0500 
Hinsen Konrad said:
> 
>    Actually, this is not true.  There are some places where coersion
>    takes place automatically, but there are lot's of places where it
>    doesn't.  In the case of numbers, witness the float() and int()
>    functions.  Similarly, lists are not automatically converted to tuples
> 
> I can't imagine a need for float() and int() except in order to
> "downgrade" a number. In all mathematical operations where floats
> are required, I can just as well use ints. Lists and tuples are
> another problem, of course.
> 
> My point of view is that as far as coercion is concerned, matrices
> should behave just like scalars of the same type(s).

But what you are unwilling to believe is that scalars do not always
coerce automatically.

Try:

  spam = '0' * 20

and

  spam = '0' * 20.0

 
>    It's not just a matter of performance.  It is also a matter of
>    correctness in some cases.  
> 
> I don't understand. The choice is automatic coercion or none at all,
> i.e. throwing an exception for mixed-type operations. I don't see
> how one or the other can lead to a wrong result; it's either the
> correct result or no result.

No, another choice is generating an incorrect result.
 
> Of course there is some chance of making a mistake and not noticing
> it due to automatic coercion, but then you already have the same
> risk with scalars. Besides, I just can't think of a reasonable
> example...

OK, how about this:

  1 / 2 * 2

as opposed to:

  1 / 2.0 * 2

These two expressions generate different results.  If I wanted the
first algorithm, I would need to explicitly force 2.0 to be an
integer, but coersion has instead forced the first sub-expression to
be a floating-point expression.

There was discussion in the Python list a while back about problems
caused by a new feature that automatically coerced floating point
values passed to functions expecting integer arguments.  Guido even
expressed regret at being talked into adding the feature.  Check the
list archive for details.

Even if an error is raised, it may be raised far from where the
coersion that ultimately caused the error was done, making debugging
of the error difficult.

As I said in my other note, I object less to coersion of element types
that to coersion of ranks.
 
> Also, I'd expect users to be familiar with coercion. I haven't
> made a survey, but I'd claim that most languages have coercion
> between numerical types, similar to Python. That's certainly
> true for the languages most used for numerical work.

Again, user's familiar with Python should not expect coersion
everywhere.

User's familiar with Fortran should certianly not expect coersion
everywhere. 
 
>    I'd be much more in favor of having different kinds of matrices that
>    automagically coerce, if people really want this.
> 
> Which creates some question and probably a lot of confusion.
> What happens if coercing and non-coercing matrices are combined?
> What happens if a function written for one type of matrices
> is used with the other? How can the matrices be distinguished
> in output?

These are certainly valid points.  Of course, the situation would be
much worse with a global variable.

Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Wed Nov  8 14:32:01 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Wed, 8 Nov 1995 09:32:01 -0500
Subject: [PYTHON MATRIX-SIG] casting and default types
In-Reply-To: <199511081356.NAA14836@qvarsx.er.usgs.GOV> (jfulton@wrdmail.er.usgs.gov)
Message-ID: <199511081432.JAA15432@cyclone.ERE.UMontreal.CA>


   > My point of view is that as far as coercion is concerned, matrices
   > should behave just like scalars of the same type(s).

   But what you are unwilling to believe is that scalars do not always
   coerce automatically.

Not at all. I am just saying that if coercion is applied to a certain
combination of scalar types, then the same coercion should be applied
to arrays of the same type.

As to which coercions should occur automatically, I'd say that int ->
float -> complex should be automatic, but the reverse not, because it
leads to an essential loss of information (int ->float can
occasionally lead to a loss of precision, depending on how long the
representations of int and float are, but I can live with that).

   > Of course there is some chance of making a mistake and not noticing
   > it due to automatic coercion, but then you already have the same
   > risk with scalars. Besides, I just can't think of a reasonable
   > example...

   OK, how about this:

     1 / 2 * 2

   as opposed to:

     1 / 2.0 * 2

That's indeed a problem, but (in my point of view) not one caused by
coercion, but by the unfortunate fact that / denotes quite different
operations for integers and for floats.

   There was discussion in the Python list a while back about problems
   caused by a new feature that automatically coerced floating point
   values passed to functions expecting integer arguments.  Guido even
   expressed regret at being talked into adding the feature.  Check the
   list archive for details.

I didn't know about that feature, and I certainly don't like it (see
above).

   As I said in my other note, I object less to coersion of element types
   that to coersion of ranks.

What exactly do you mean by "coercion of ranks"?

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Wed Nov  8 15:06:28 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Wed,  8 Nov 95 10:06:28 -0500
Subject: [PYTHON MATRIX-SIG] casting and default types
References: <199511081432.JAA15432@cyclone.ERE.UMontreal.CA>
Message-ID: <9511081506.AA13100@nineveh.lcs.mit.edu.LCS.MIT.EDU>


> What exactly do you mean by "coercion of ranks"?

I'm responsible for this poor phrase.  My initial matrix proposal had the  
phrase "dimension coercion" for the J-style rank concept (of which I was  
unaware at the time).

The issue in a nutshell is that everybody (I think) agrees that:

a = Matrix((1,2,3),(11,12,13))
b = Matrix(100,200,300)

a+1 = Matrix((2,3,4),(12,13,14))

One question is should a+b be an error, or should it be

a+b = Matrix((101,202,203),(111,212,313))

I believe that the second is correct, and this can be elegantly expressed  
by the concept of ranks.  I don't think there's much disagreement on this  
either.

Now the question comes, what if I ask for inverse( Matrix(((1,2),(11,12)),  
((3,4),(13,14))) ).

Using the rank notions in J, the argument should be considered a 1-frame of  
2-cells.  The result should be a 1-frame containing the inverse of each of  
these 2-cells.

However, for a case like this one, the arguments in favor of treating this  
as an error (you can't take the inverse of a 3d matrix) seem worth  
considering.

My current solution to this is that my optimized ofuncs use the J-style  
rank system, but only work on operations with unbounded rank like +, *, etc.  
 This is as much an implementation issue as anything else.

Other functions on matrices, like inverse (or my favorite, fft) are  
completely free to implement a rank system, or not as they see fit.  So for  
the fft function, when given a matrix, it will return the fft of every  
1-cell.  The question is whether or not we should adopt such a system as a  
standard for matrix functions.  Under the current setup there would be no  
way to enforce such a standard.

-Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Wed Nov  8 15:47:35 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Wed, 8 Nov 1995 10:47:35 -0500
Subject: [PYTHON MATRIX-SIG] casting and default types
In-Reply-To: <9511081506.AA13100@nineveh.lcs.mit.edu.LCS.MIT.EDU> (message from James Hugunin on Wed,  8 Nov 95 10:06:28 -0500)
Message-ID: <199511081547.KAA19928@cyclone.ERE.UMontreal.CA>


   Using the rank notions in J, the argument should be considered a 1-frame of  
   2-cells.  The result should be a 1-frame containing the inverse of each of  
   these 2-cells.

   However, for a case like this one, the arguments in favor of treating this  
   as an error (you can't take the inverse of a 3d matrix) seem worth  
   considering.

In my opinion, the experience of the APL/J community shows that using
rank extension everywhere is the better solution. Although in
principle that can hide errors, such errors don't seem to occur in
practice.  It happens that by some mistake you create an array with
the wrong length (typically off by 1), but you never create an array
of the wrong rank. Besides, you could always locate such a mistake
after a rank-3 inversion, as the result is still rank-3 and could
not be confused with the inverse of a rank-2 matrix.

On the other hand, there are applications where rank extension on
inverses etc. is useful. Of course you could always get the same
effect with explicit loops, but the speed difference is enormous
(e.g. for inverting 1000 4x4 matrices).

   My current solution to this is that my optimized ofuncs use the J-style  
   rank system, but only work on operations with unbounded rank like +, *, etc.  

That includes all binary operations, which are the most complicated.

   Other functions on matrices, like inverse (or my favorite, fft) are  
   completely free to implement a rank system, or not as they see fit.  So for  

There should be some provision in the matrix module for applying
a unary function with a given rank to an array of higher rank,
which could also be applied to user-written Python functions.

   the fft function, when given a matrix, it will return the fft of every  
   1-cell.  The question is whether or not we should adopt such a system as a  

FFT is a good example for an operation where the rank system is useful.
There are of course many applications for rank-1 FFT with extension to
higher ranks, i.e. what you implemented. But it also makes sense
to have multidimensional FFTs. In the J system, FFT would be unbounded
and therefore n-dimensional for a rank-n array. You could then
specify a lower rank to get lower-dimensional FFTs.

   standard for matrix functions.  Under the current setup there would be no  
   way to enforce such a standard.

I think it should be standard (i.e. provided for all built-in functions).
It shouldn't be enforced for user-defined function, but it should be
made easy.

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From dubois@kristen.llnl.gov  Thu Nov  9 19:10:44 1995
From: dubois@kristen.llnl.gov (P. Dubois)
Date: Thu, 9 Nov 1995 11:10:44 -0800
Subject: [PYTHON MATRIX-SIG] A related idea
In-Reply-To: <9511071456.AA11707@nineveh.lcs.mit.edu.LCS.MIT.EDU> (message
 from James Hugunin on Tue, 7 Nov 95 09:56:39 -0500)
Message-ID: <9511091910.AA08047@kristen.llnl.gov>

Jim Hugunin replied, in response to my suggestion for providing an
"adoption" method for compiled arrays:
   > Suppose we have the matrix class working.

   What do you mean suppose ;)  ?

Hey, I'm a mathematician, all my sentences start with suppose!

   > Suppose there is a Fortran
   > or C array in the program which you would like to "adopt" as a
   > matrix in Python. The only difference between this and a matrix created a
   > normal way is that you have to remember never to free the memory.
   > So it seems you might be able to do this if you had a method
   > of creation (from C) which took a pointer,size,type kind of
   > description. You could then increment the reference counter one extra, so
   > that the memory is never freed, or a "don't free" flag could be in the
   > header.

   I agree that there should be a function to create a new matrix object from  
   an existing array in C (or FORTRAN).  What we disagree about is the  
   semantics.  I played around a while with the idea of "sharing" an array  
   between python and C.  I found that as a general rule I ran into memory leak  
   problems (or worse).  Using your scheme, python is never responsible for  
   freeing the allocated memory, this means that the C code must be responsible  
   for it, but the C code can't know when it is safe to free the memory  
   because even when it's done with it there might still be a python reference  
   to the memory.

   Let me know if I'm completely missing something here, and this memory leak  
   issue isn't really a problem.

   <snip>

This is a good point which I hadn't thought of because the way I intend to
use this "adopting" the arrays are the permanent state of a calculation and
are never "released" by the compiled code. I was aware that if I wanted to
ever change size etc. I would somehow need to tell Python about it. Some
careful thinking is required in that case.

The point isn't that I want to save memory but that I want to MODIFY the
array the compiled code is using, such as an array in a Fortran common block.
I don't have a problem copying it when I'm going to do something with it.
But to use it as a method of input to a code, I need to be able to do
something like:

import phys1 #load up physics code
phys1.x = <matrix expression>
# or
phys1.x[3] = 1.

Here I'm assuming x is created by the initialization of the module such
that it has the "real" x in the compiled code as a data area.

Obviously, one could instead provide methods (e.g., set_x, set_y, set_z)
but it dispels the illusion that x is really a matrix attribute of a physics
package.

Maybe I'm not taking the right approach here. Suggestions appreciated.














=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From dubois@kristen.llnl.gov  Fri Nov 10 16:40:40 1995
From: dubois@kristen.llnl.gov (P. Dubois)
Date: Fri, 10 Nov 1995 08:40:40 -0800
Subject: [PYTHON MATRIX-SIG] [munro@icf.llnl.gov: Re: Python Matrix extension tutorial]
Message-ID: <9511101640.AA18754@kristen.llnl.gov>

Dear Matrix-SIGers,
   Yesterday at LLNL Brian Yang taught a tutorial on the matrix extension
to about 20 people. I asked that people give me comments to forward to
the SIG. In general, we concluded that the extension does 
what we need it to do. Here are some of the comments for your consideration.
I will send them as separate messages so as to compartmentalize the discussion
a little. The first is from Dave Munro. Dave is a physicist who has developed
his own interpreted language for postprocessing called Yorick. The code this
is most often used to postprocess, Lasnex, is a Fortran program with lots of
arrays, so Yorick has facilities especially devoted to manipulating arrays
easily. Here is Dave's suggestion:
------- Start of forwarded message -------

In the handout at the meeting on page 7 is an example of the heavily
used Yorick feature I mentioned: You have two arrays

   b  with shape (2,3)
   c  with shape (2,2,3)

and you want to produce:

   d[i][j][k]= b[i][k] + c[i][j][k]

{The example would be much clearer if the ranks were given as (2,3)
and (2,4,3), so it only made sense one way.}  In Python, this common
operation is carried out by the expression:

   d= add[1,2](b,c)

Yorick has a special syntax for this same operation:

   d= b(,-,) + c

which I find much clearer; the "-" in an index list is a place holder
indicating that the result is to have an additional dimension in the
slot where the "-" was.  Thus b(,-,) is a rank-3 array which can be
directly compared with c.  With this notation, b(,,-)+c is the same as
b[j][k]+c[i][j][k] (the default), while b(,-,)+c produces
b[i][k]+c[i][j][k] and b(-,,)+c produces b[i][j]+c[i][j][k].  I call
the "-" a "pseudo-index" in Yorick.

In order for this to work, you need to broaden the definition of when
two arrays are conformable; instead of requiring an exact match for
the shape of the largest common cells of the two operands, you need to
treat 1-length dimensions as "wildcards" matching any length.  Thus,
if b has shape (2,3) then b(,-,) has shape (2,1,3) -- exactly the same
as reshape(b, (2,1,3)) -- which you can consider conformable to the
(2,4,3) array c by the rule that [i][0][k] matches [i][j][k].
Ordinary scalar broadcasting is just a specific case of this general
conformability rule.

-----

I have the impression that the syntax would present very little
difficulty in Python; on the model of the All and Reverse index
objects, it would be easy to introduce a Pseudo object which did the
reshape:

   d= b[(All,Pseudo,All)] + c

However, I imagine that the implementor will be loathe to change his
notion of array conformability at this late date.  Nevertheless, you
might as well ask to see what he says; probably the change wouldn't
actually break any existing correct code, but merely give meaning to
what would previously have produced a runtime error.  That "1-length
wildcard" rule has been a tremendous winner for Yorick; if you can
convince the Python guys to use it, I doubt they would ever regret it.

In Yorick, the combination of the relaxed conformability rule,
pseudo-indices and a general transpose operator that can produce any
permutation of dimensions allows for nearly all meaningful
combinations of arrays.

-----

Yorick has one other indexing syntax which has proven useful, which I
call "rubber indices".  They address the problem of writing
interpreted code which extracts slices of arrays when you don't know
beforehand how many dimensions the array has.  An example is an
opacity array for which you know that the most slowly varying index
represents photon wavelength, but there might be zero, one, two, or
three faster varying dimensions representing position in space.  These
situations can probably be handled with Python's reshape operator, so
again this is a question of ease of use.

------- End of forwarded message -------



=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From dubois@kristen.llnl.gov  Fri Nov 10 16:53:01 1995
From: dubois@kristen.llnl.gov (P. Dubois)
Date: Fri, 10 Nov 1995 08:53:01 -0800
Subject: [PYTHON MATRIX-SIG] [tbyang@icf.llnl.gov: Some subtlety in reaching items of a matrix]
Message-ID: <9511101653.AA18832@kristen.llnl.gov>

The following comment by Brian Yang is not a surprise, as the difference in
returning reference vs. returning copy was documented, but I thought I'd
pass it on.
------- Start of forwarded message -------
	I just found something about the matrix module which I was not
aware of earlier:
 For a rank-3 matrix `c', there are some subtle difference between
C[0][1] and c[(0,1)]. The following example illustrates this:

----------------------------------------->
>>> c [[[4.0, 5.0, 6.0],
[0.0, 4.0, 5.0]], [[1.0, 6.0, 5.0], [8.0, 5.0, 2.0]]]
>>> c2=c[(0,1)]
>>> c2 
[0.0, 4.0, 5.0] 
>>> c1=c[0][1] 
>>> c1 
[0.0, 4.0, 5.0] 
>>> c[(0,1,2)]=6 
>>> c 
[[[4.0, 5.0, 6.0], [0.0, 4.0, 6.0]], [[1.0, 6.0, 5.0], [8.0, 5.0, 2.0]]] 
>>> c1 
[0.0, 4.0, 6.0] 
>>> c2 
[0.0, 4.0, 5.0]
<-------------------------------------- 
Notice when c changes, c1 changes also, but not c2.
	The difference occurs because in `c1=c[0][1]' c is treated as
a sequence, while in `c2=c[(0,1)]' c is treated as a mapping. And it
just so happened that in the implementation of the methods, Hugunin
decided to create a new matrix in the latter case, while for the
former case he just created some new pointers pointing to the same
data area as c. It appears very confusing to me. If we can have enough
feed-back about this, maybe we can suggest him to change to one way or
the other.

------- End of forwarded message -------


=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Fri Nov 10 17:08:37 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Fri, 10 Nov 95 12:08:37 -0500
Subject: [PYTHON MATRIX-SIG] [tbyang@icf.llnl.gov: Some subtlety in
 reaching items of a matrix]
References: <9511101653.AA18832@kristen.llnl.gov>
Message-ID: <9511101708.AA00801@ling-ling.lcs.mit.edu.LCS.MIT.EDU>


> For a rank-3 matrix `c', there are some subtle difference between
> C[0][1] and c[(0,1)]. The following example illustrates this:

<snip>

First, I agree completely, this is terrible.  Nevertheless, here's my  
justification:

Returning a matrix by-copy is always the best thing to do conceptually (I  
guess I've played with too many functional languages).  I find it a lot  
easier to think about my matrix code if I don't have to worry about  
references to objects.

On the other hand, if you want to allow python indexing of the style  
a[i][j] to function with any sort of reasonable efficiency, then you need to  
have a[i] return by reference.

I'm perfectly willing to be convinced to change over to always returning  
matrices by reference (with the understanding that the code will have many  
more bugs, and the understanding that if a = Matrix(1,2,3) then a[0] will  
return not a python float, but a 0d matrix with the same sort of reference  
style semantics) or to always returning arrays by copy with the  
understanding that a[i][j] will potentially be an incredibly inefficient way  
of accessing an array element.

I'm not happy with my chosen compromise.  I just can't come up with a  
better solution.

-Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From dubois@kristen.llnl.gov  Fri Nov 10 17:20:09 1995
From: dubois@kristen.llnl.gov (P. Dubois)
Date: Fri, 10 Nov 1995 09:20:09 -0800
Subject: [PYTHON MATRIX-SIG] [tbyang@icf.llnl.gov: Some subtlety in
 reaching items of a matrix]
In-Reply-To: <9511101708.AA00801@ling-ling.lcs.mit.edu.LCS.MIT.EDU> (message
 from James Hugunin on Fri, 10 Nov 95 12:08:37 -0500)
Message-ID: <9511101720.AA19051@kristen.llnl.gov>

I think we will sooner or later get time to make the change discussed before
so that c[0,1] is a euphemism for c[(0,1)]. Assuming that, allowing
c[0][1] to be a reference while c[0,1] is a copy
doesn't seem too hard to explain to people. And I think the latter will 
be used much more than the former for use in expressions. 

I think the compromise adopted is far better than the alternatives; this 
class has to have good performance and we certainly want easy ways to 
assign values to row and columns at vector speed. 

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Fri Nov 10 17:45:43 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Fri, 10 Nov 95 12:45:43 -0500
Subject: [PYTHON MATRIX-SIG] [tbyang@icf.llnl.gov: Some subtlety in
 reaching items of a matrix]
References: <9511101737.AA00683@garion.llnl.gov.llnl.gov>
Message-ID: <9511101745.AA00962@ling-ling.lcs.mit.edu.LCS.MIT.EDU>


> If c[0,1] becomes a euphemism for c[(0,1)]. I will be very confused in
> interpreting c[0], as it can correpond to both c[0,1] and c[0][1], if
> they do different things.

This is in a very good point!  Just so you know how things will work (if no  
changes are made).

c[0] will be a reference to the data in c, and c[0,] will be a copy of the  
data in c.  This is incredibly ugly, but again, I don't know what to do  
about it.

-Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Fri Nov 10 20:18:59 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Fri, 10 Nov 95 15:18:59 -0500
Subject: [PYTHON MATRIX-SIG] [munro@icf.llnl.gov: Re: Python Matrix
 extension tutorial]
References: <9511101640.AA18754@kristen.llnl.gov>
Message-ID: <9511102019.AA01218@ling-ling.lcs.mit.edu.LCS.MIT.EDU>


First off, I want to mention that I've looked at Yorick and find it a very  
impressive language for matrix manipulation.  If I was still trying to  
choose between languages like octave or matlab I'd find Yorick a clear  
winner.  The point of this python extension is to put these sorts of  
features within the python language so that so that we can simultaneously  
have access to the full power of that programming language (I know of no  
other "matrix" language in which you can write a full-scale web browser).

> In the handout at the meeting on page 7 is an example of the heavily
> used Yorick feature I mentioned: You have two arrays
>
>    b  with shape (2,3)
>    c  with shape (2,2,3)
>
> and you want to produce:
>
>    d[i][j][k]= b[i][k] + c[i][j][k]
>
> {The example would be much clearer if the ranks were given as (2,3)
> and (2,4,3), so it only made sense one way.}  In Python, this common
> operation is carried out by the expression:
>
>    d= add[1,2](b,c)
>
> Yorick has a special syntax for this same operation:
>
>    d= b(,-,) + c
>
> which I find much clearer

I think that Dave has a different concept of the operation being indicated  
by add[1,2](b,c) than I do, and than is really suggested by the notion of  
ranks.  add[1,2] means add the vectors in b to the matrices in c.  The  
notion of producing d[i][j][k]= b[i][k] + c[i][j][k] is conceptually  
different.  Nevertheless, I am intrigued by the idea of adding this to the  
language.

> I have the impression that the syntax would present very little
> difficulty in Python; on the model of the All and Reverse index
> objects, it would be easy to introduce a Pseudo object which did the
> reshape:
>
>    d= b[(All,Pseudo,All)] + c
>
> However, I imagine that the implementor will be loathe to change his
> notion of array conformability at this late date.  Nevertheless, you
> might as well ask to see what he says; probably the change wouldn't
> actually break any existing correct code, but merely give meaning to
> what would previously have produced a runtime error.  That "1-length
> wildcard" rule has been a tremendous winner for Yorick; if you can
> convince the Python guys to use it, I doubt they would ever regret it.

I think that this makes sense, and I'll have a go at implementing it for my  
next release.  The current version of the matrix object is 0.11 for a  
reason.  I'm perfectly happy to consider any and all suggested changes to  
the language.  I think I need to play with this one a little bit to see if I  
like it (for most of the things that I do ranks really are the right  
conceptual model), and I'll throw it out so that other people can begin  
playing with it and form their own opinions.

> Yorick has one other indexing syntax which has proven useful, which I
> call "rubber indices".  They address the problem of writing
> interpreted code which extracts slices of arrays when you don't know
> beforehand how many dimensions the array has.  An example is an
> opacity array for which you know that the most slowly varying index
> represents photon wavelength, but there might be zero, one, two, or
> three faster varying dimensions representing position in space.  These
> situations can probably be handled with Python's reshape operator, so
> again this is a question of ease of use.

I think that I like this idea.  Let me know if this is what you mean.

Currently I have (for c being a 3d array):
c[[0,]] <--> c[[0,All, All]]

Are you suggesting something like:

c[[Rubber, 0]] <--> c[[All, All, 0]]?

If you're in fact suggesting something else, I'd like to hear more.

-Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Fri Nov 10 21:36:20 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 10 Nov 1995 16:36:20 -0500
Subject: [PYTHON MATRIX-SIG] [munro@icf.llnl.gov: Re: Python Matrix extension tutorial]
In-Reply-To: <9511101640.AA18754@kristen.llnl.gov> (dubois@kristen.llnl.gov)
Message-ID: <199511102136.QAA24733@cyclone.ERE.UMontreal.CA>


   Yorick has one other indexing syntax which has proven useful, which I
   call "rubber indices".  They address the problem of writing
   interpreted code which extracts slices of arrays when you don't know
   beforehand how many dimensions the array has.  An example is an
   opacity array for which you know that the most slowly varying index
   represents photon wavelength, but there might be zero, one, two, or
   three faster varying dimensions representing position in space.  These
   situations can probably be handled with Python's reshape operator, so
   again this is a question of ease of use.

Maybe it helps to point out how this is handled in J and in my Array
module. There indexing is not seen as something special, but just as
one of many structural functions. Consequently it has no special
syntax (in my array module I have added bracket indexing as a kind of
syntactic sugar for the function take()), but is an ordinary function
with two arguments: the array to be indexed from, and an index array.

Accessing the first (or second etc.) dimension of an array of
arbitrary rank is then done by specifying a negative rank for the
indexing function. Negative function ranks basically mean that you do
not specify the rank of the cells that the function operates on, but
the rank of the frames of these cells. Maybe something similar could
be implemented in Python, although I don't see with what kind of
syntax one could indicate negative ranks for bracket indexing.

Personally, I'd like to see an additional indexing function similar in
spirit to the J version. I realise it can't replace bracket indexing,
since you can't assign to parts of a matrix this way, but it would be
a useful addition for many cases.

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From chris.chase@jhuapl.edu  Fri Nov 10 22:20:00 1995
From: chris.chase@jhuapl.edu (Chris Chase S1A)
Date: Fri, 10 Nov 1995 17:20:00 -0500
Subject: [PYTHON MATRIX-SIG] Yorick, Python and Array.py
Message-ID: <199511102212.RAA00670@python.org>


>>>>> "D" == Dave Munro

D> Here is Dave's suggestion:

[deleted material about pseudo indexes and comformability in Yorick]

Two weeks ago someone pointed me toward the Yorick language for its
array capabilities.  After studying it, I found that Yorick has the
most flexible array subscripting syntax of any language that I have
seen.

The advantages of Yorick can be added to Python but it requires some
major work on some internals.  In a reply to one of my previous posts,
Guido already said he doesn't mind someone submitting internal changes
that keep the language backward compatible.  I have been working on
these modifications and hope to finish them soon (I don't have much
time available for this SIG and tinkering around with Python).  I will
post a summary of the changes in a separate message that I attempting
to get some immediate feedback before I finish my mods.

D> In order for this to work, you need to broaden the definition of when
D> two arrays are conformable; instead of requiring an exact match for
D> the shape of the largest common cells of the two operands, you need to
D> treat 1-length dimensions as "wildcards" matching any length.  

I already have tried this by making a small modification to Array.py,
the prototype from Konrad Hinsen <hinsenk@ere.umontreal.ca>.  If
anyone is interested I can send you the modified version.

Array.py already has a concept of wildcard for extending a shorter
frame for one argument to match a longer frame of another argument.
It does this by combining the lower-rank array will then be combined
with each matching ranked cell in the higher ranked array.  Yorick
calls this broadcasting because the lower ranked cell is "broadcasted"
or replicated along the missing higher dimensions.

Yorick extends this one step further.  Yorick will broadcast along any
size 1 dimension to match the common dimension of the other arguments.
When combining a lower rank array with a higher rank we can think of
the missing higher dimensions as being size 1.  (i.e. equivalent to
appending 1's to the shape of the shorter frame).  Then the
broadcasting method will have the same behavior already exhibited by
Array.py.

However, it has the additional benefit of broadcasting other unit
dimensions (a simple viewpoint unit dimensions have similar behave
like a scalar.)  

As an example, using the modified Array.py:
b = Array([ [2,3,7], [9,8,2] ])
d = Array([1,2,3])
e = Array([[1],[2]])

# This could already be done.  It adds to each row.
>>> b+d
 3  5 10 
10 10  5 

# This is new. It adds a column vector containing 1,2 to each column.
>>> b+e
 3  4  8 
11 10  4 

It makes outer products extremely simple:

>>> d+e
2 3 4 
3 4 5 
>>> d*e
1 2 3 
2 4 6 

Pseudo indexes make this type of thing even easier.

In the above if e=Array([1,2]) then I could have added e along the
columns using: b+e(-,)

This is more useful in even higher dimensions.  It saves pairs of
transposition operators and/or reshaping which can be confusing.

D> However, I imagine that the implementor will be loathe to change his
D> notion of array conformability at this late date.  Nevertheless, you
D> might as well ask to see what he says; probably the change wouldn't
D> actually break any existing correct code.

There is no single "implementor" here.  My understanding is that the
Matrix module concept is still in flux - hence the need for this SIG.
There have been several implementations and design concepts suggested
on this list.  I have not seen any proposal to accept as a standard a
particular Array module yet.

D> In Yorick, the combination of the relaxed conformability rule,
D> pseudo-indices and a general transpose operator that can produce any
D> permutation of dimensions allows for nearly all meaningful
D> combinations of arrays.

I do like Yorick's completely general transpose() operator which uses a
list of permutation cycles combined with circular shifts and negative
dimension numbers (taken relative to the rank) to conveniently specify
any arbitrary transposition on dimensions.

D> Yorick has one other indexing syntax which has proven useful, which I
D> call "rubber indices".  

This is another very useful feature.  The idea is that you can have
left or right justified index lists relative to array
rank. Unspecified dimensions indexes default to the entire dimension.
Optionally, the unspecified dimensions can be collapsed into a single
dimension that is the product of the collapsed dimensions.  Yorick
provides a very nice syntax for a rubber index ".." and "*" to
collapse the missing indexes.  This becomes very useful when the
dimension is unknown to the user and provides much simpler and clearer
code than a complex sequence of take() and reshape() operators.

b(..,2,3) or b(*,2,3) index along the last two dimensions.  b(1,..,5)
indexes along the first and last dimension.  Indexes before the rubber
index are left-justified while those following the rubber index are
right-justified with respect to the shape of the indexed array.

One other subscripting feature that Yorick (Matlab has this also)
has is the ability to specify a stride with slice notation.
E.g. 1:10:2 specifies a range the has increments of 2.  The stride can
also be negative.  This is like the range() function.

I list the additions that I am experimenting with in another post.

Chris

------- end -------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Fri Nov 10 22:33:52 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Fri, 10 Nov 95 17:33:52 -0500
Subject: [PYTHON MATRIX-SIG] Yorick, Python and Array.py
References: <199511102212.RAA00670@python.org>
Message-ID: <9511102233.AA01268@ling-ling.lcs.mit.edu.LCS.MIT.EDU>


> The advantages of Yorick can be added to Python but it requires some
> major work on some internals.  In a reply to one of my previous posts,
> Guido already said he doesn't mind someone submitting internal changes
> that keep the language backward compatible.

I'm not sure that this is true.  I've found that for my matrix object (on  
which I have received almost entirely good reviews from the testers) that  
this sort of indexing can be added very easily to python using mapping  
semantics (as Dave mentioned):

ie. a[[All,Empty,All]] <--> a(,-,)

I do think that it would be nice to remove that extra set of brackets,  
which Guido is also in favor of; however, I'm just not convinced that any  
further modifications are needed.

For your other examples:

a[[Star,2,3]] <--> a(*,2,3)

a[[Slice(1,10,2)]] <--> a(1:10:2)

I realize that the syntax in Yorick is a little bit more consise, but I'm  
just not convinced that such fundamental changes to the python core are in  
fact necessary.

Just my two cents worth,
Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Thu Nov  9 19:47:10 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Thu, 9 Nov 1995 14:47:10 -0500
Subject: [PYTHON MATRIX-SIG] A related idea
In-Reply-To: <9511091910.AA08047@kristen.llnl.gov> (dubois@kristen.llnl.gov)
Message-ID: <199511091947.OAA14508@cyclone.ERE.UMontreal.CA>


   The point isn't that I want to save memory but that I want to MODIFY the
   array the compiled code is using, such as an array in a Fortran common block.

We should make a difference between Fortran and C interfacing (C
standing for all languages that can handle dynamic memory management
in a reasonable way). Fortran arrays are always static, so there
is no memory leak problem. Increasing the reference count to make
sure Python never tries to free the memory should be sufficient.

As for C, the best way would be to leave allocation completely to
Python. The matrix module would provide functions to allocate and free
matrices that can be called from the C code just like malloc() and
free(). These functions would take care of the reference from the C
code.

Of course the C code is also free to handle its own matrices and
manage them completely (e.g. workspace in library functions). These
would never be accessed from Python; in fact, Python wouldn't even
know about their existence.

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From chris.chase@jhuapl.edu  Sat Nov 11 06:01:27 1995
From: chris.chase@jhuapl.edu (Chris Chase S1A)
Date: Sat, 11 Nov 1995 01:01:27 -0500
Subject: [PYTHON MATRIX-SIG] Yorick, Python and Array.py
In-Reply-To: <9511102233.AA01268@ling-ling.lcs.mit.edu.LCS.MIT.EDU>
References: <199511102212.RAA00670@python.org>
 <9511102233.AA01268@ling-ling.lcs.mit.edu.LCS.MIT.EDU>
Message-ID: <199511110601.BAA02636@python.org>

>>>>> "JH" == James Hugunin <jjh@mama-bear.lcs.mit.edu> writes:

JH> I'm not sure that this is true.  I've found that for my matrix object (on  
JH> which I have received almost entirely good reviews from the testers) that  
JH> this sort of indexing can be added very easily to python using mapping  
JH> semantics (as Dave mentioned):

JH> ie. a[[All,Empty,All]] <--> a(,-,)

I guess I am not clear on this.  Are All and Empty special objects
defined by your matrix module?

Aside: Actually, if the additions I had in mind were made (like slice
notation) I would write the righthand side as a[:,-,:] or a[:,None,:],
avoiding a new syntactic element for an empty argument (not seen
elsewhere in the language).

If you are concerned about too many extras added to the language, I
would suggest that None be equivalent to "-", removing the requirement
for your Empty object.

JH> I do think that it would be nice to remove that extra set of brackets,  
JH> which Guido is also in favor of; however, I'm just not convinced that any  
JH> further modifications are needed.

As you have indicated, there are clever workarounds that can
accomplish the Yorick type of additions without internal language
changes.  However, I do not think that we should rule out internal
Python additions if they are beneficial but don't break, limit,
or violate the spirit/flavor of the language.

JH> a[[Star,2,3]] <--> a(*,2,3)

Okay.  This is good.  Would you use something like Dot for the Yorick
".." pseudo index?

How do you keep the definitions of Star and Dot from being hidden
inadvertently by other definitions in the users code (like an imported
star catalog module that defines a Star object)?

JH> a[[Slice(1,10,2)]] <--> a(1:10:2)

Would the following also work?

a[::2,:-4,::-1]  <--> a[[Slice(None,None,2),Slice(None,-4),Slice(None,None,-1)]]

This is product indexing on a, i.e. the indexes of the resulting
elements are taken from the Cartesian product of the index vectors.
This example takes every other on the first dimension, up to the fourth
from the last on the second dimension, and reverses the last dimension.

Of course one may want to mix scalars, slices, and matrices as indexes
in the same subscripting expression:

a[(1,2,3),5,::-1,b] <--> a[[[1,2,3],5,Slice(None,None,-1),b]]

Are you also considering supporting indexing a multi-dimensional array
in flattened form when only a single index vector is given?  E.g. for
the rank 3 a:

a[[Slice(1,None,2)]] accessing every other element of a in flattened
form.  This is useful and common in other array languages.

The danger here is that a[[[1,2,3]]] could be mistaken for a[[1,2,3]],
where the first is a one-dimensional 3 element vector index into a
flattened array and the second is a multi-dimensional index using a
scalar for each dimension.  (Dropping the extra grouping, the
difference a[(1,2,3)] and a[1,2,3] is slightly more evident).

JH> I realize that the syntax in Yorick is a little bit more consise, but I'm  
JH> just not convinced that such fundamental changes to the python core are in  
JH> fact necessary.

Necessary, perhaps not.  Worthwhile, I would definitely say
yes. (Especially if someone volunteers the work for the changes).  

At the least, I feel the following would be worthwhile:

1) drop the extra grouping inside [] for multi-dimensional subscripts.
2) support slice expressions with strides wherever a 'test'
   syntactical element is possible. This internalizes your Slice()
   functionality.  It is a natural extension of slice syntax already
   available.  But requires a special check for calling the current
   __slice__ functionality for sequences.

Mabye:
3?) '-' for pseudo index [not a big benefit but it only takes 3 lines
    of code, one in Grammar and 2 in compile.c] 

I have already started implementing these.  I think that your
workaround for the rubber indexes is just as good as what I had
started to implement (probably better in the how it fits into the
language philosophy).

Aside: It would have been useful if the Python methods for sequence
and dictionary types (e.g. __slice__) had originally been defined to
take variable length argument lists instead of defined length and type
argument lists.  Then additions for slices with strides and
multi-dimensional indexing would have been easier to add without
breaking existing code (argument checking would be up to the method.
If more arguments then desired were passed, e.g. 3 instead of 2 for a
slice, then either the extra arguments would be ignored or an
exception signaled.  Similarly for subscripting.).

Chris Chase

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Sat Nov 11 17:17:10 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Sat, 11 Nov 95 12:17:10 -0500
Subject: [PYTHON MATRIX-SIG] Yorick, Python and Array.py
References: <199511102212.RAA00670@python.org>
 <9511102233.AA01268@ling-ling.lcs.mit.edu.LCS.MIT.EDU>
 <9511110559.AA08773@mama-bear.LCS.MIT.EDU>
Message-ID: <9511111717.AA01573@ling-ling.lcs.mit.edu.LCS.MIT.EDU>


I almost completely agree with your comments (now that I think I better  
understand what you're talking about).  Here is how I see things.  Please  
shout out if there are any major errors.

I'm creating special objects All, Empty, Star, and Dot in order to capture  
the capabilities of Yorick for array subscripting.

I've created a slice object to generalize the notion of start:stop:step indexing.

Right now, my indexing system can take any combination of arbitrary  
sequences of ints, slices, or single ints as a full product form index into  
the matrix.

The principle problems with this system are potential naming conflicts (or  
really ugly names like Matrix.Star) and the ugliness of Slice(None,None,2)  
vs. ::2.

You are working on an extension to the python grammar to remove the extra  
brackets, make ::2 <--> some builtin python slice object, and "-" equivalent  
to some builtin python pseudo index object.  I'd love to see all of these  
things happen, and I think that they'd fit in perfectly with my existing  
matrix object.

I'm curious as to how you're implementing your slices.  Are you creating a  
new python C object?  This is actually the next step for me with my matrix  
object, and I'd love to see what you've done so far so that I can try and  
keep my work compatible with yours (and not duplicate too much effort).

-Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Sun Nov 12 17:22:18 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Sun, 12 Nov 1995 12:22:18 -0500
Subject: [PYTHON MATRIX-SIG] Yorick, Python and Array.py
In-Reply-To: <9511111717.AA01573@ling-ling.lcs.mit.edu.LCS.MIT.EDU> (message from James Hugunin on Sat, 11 Nov 95 12:17:10 -0500)
Message-ID: <199511121722.MAA19828@cyclone.ERE.UMontreal.CA>


   I'm creating special objects All, Empty, Star, and Dot in order to capture  
   the capabilities of Yorick for array subscripting.

I confess that I have not yet completely studied all the discussion
about indexing, but let's not get carried away to fast with
implementations.  We are not creating matrices for Yorick users, but
for Python, so the notation we introduce should make sense without
referring to Yorick.  "All" and "Empty" are fine, but how should
anyone make sense of "Star" and "Dot" without learning Yorick first?

We should first agree on what features we want (preferably based on
real use in other matrix languages) and then think about a notation
for them that fits into Pythons general structure. For example, I
don't like the idea of having '-' standing for anything else than
a mathematical operation; once we start with this, we'll soon have
a Perl-compatible letter soup.

   I've created a slice object to generalize the notion of start:stop:step indexing.

That's not the worst solution, but maybe there is a better one. How
about permitting lists of indices? That would include the generalized
slices if range() is used to create the list. But it would also allow
much more general indexing schemes without any further effort. It is
probably a bit less efficient, but are generalized slices really used
in time-critical parts of matrix algorithms? (Honest question, I don't
know!)

   The principle problems with this system are potential naming conflicts (or  
   really ugly names like Matrix.Star) and the ugliness of Slice(None,None,2)  
   vs. ::2.

Indeed. It would not be too difficult to allow ::2 as valid syntax,
but that raises the question of what this means for other Python
objects. For consistency it should be implemented everywhere. Is
anyone volunteering to do that?

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Sun Nov 12 18:30:58 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Sun, 12 Nov 95 13:30:58 -0500
Subject: [PYTHON MATRIX-SIG] Yorick, Python and Array.py
References: <199511121722.MAA19828@cyclone.ERE.UMontreal.CA>
Message-ID: <9511121830.AA01870@ling-ling.lcs.mit.edu.LCS.MIT.EDU>


>    I'm creating special objects All, Empty, Star, and Dot in order to capture  
>    the capabilities of Yorick for array subscripting.
>
> I confess that I have not yet completely studied all the discussion
> about indexing, but let's not get carried away to fast with
> implementations.  We are not creating matrices for Yorick users, but
> for Python, so the notation we introduce should make sense without
> referring to Yorick.  "All" and "Empty" are fine, but how should
> anyone make sense of "Star" and "Dot" without learning Yorick first?

I love the discussions that this list has generated, nonetheless I have  
found that sometimes they remain a little bit too divorced from actual  
implementations.  I'm trying to implement some of the more interesting ideas  
in the hopes of myself and others being able to play with them, not as an  
attempt to impose a standard!

> We should first agree on what features we want (preferably based on
> real use in other matrix languages) and then think about a notation
> for them that fits into Pythons general structure. For example, I
> don't like the idea of having '-' standing for anything else than
> a mathematical operation; once we start with this, we'll soon have
> a Perl-compatible letter soup.

This is a very good point.

>   I've created a slice object to generalize the notion of start:stop:step  
indexing.
>
> That's not the worst solution, but maybe there is a better one. How
> about permitting lists of indices? That would include the generalized
> slices if range() is used to create the list. But it would also allow
> much more general indexing schemes without any further effort. It is
> probably a bit less efficient, but are generalized slices really used
> in time-critical parts of matrix algorithms? (Honest question, I don't
> know!)

Gee Konrad, I thought you had been playing with my matrices.  I already  
allow lists of indices, and it's true, you can create generalized slices  
using range.  The slice object is there in order to make things a lot  
easier.  One thing that I really like about slices is that you can leave off  
the start or end points, and have them assigned appropriately for the array  
(just as in normal python slice indexing).  This is a LOT easier to use  
than range.

-Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Sun Nov 12 18:47:31 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Sun, 12 Nov 1995 13:47:31 -0500
Subject: [PYTHON MATRIX-SIG] Yorick, Python and Array.py
In-Reply-To: <9511121830.AA01870@ling-ling.lcs.mit.edu.LCS.MIT.EDU> (message from James Hugunin on Sun, 12 Nov 95 13:30:58 -0500)
Message-ID: <199511121847.NAA22095@cyclone.ERE.UMontreal.CA>


   implementations.  I'm trying to implement some of the more interesting ideas  
   in the hopes of myself and others being able to play with them, not as an  
   attempt to impose a standard!

Fine, but there is always the danger that the first working implementation
sets a de-facto standard. That's how we got "industry standards" like
DOS, Windows, or the IBM PC architecture.

Maybe it would be a good idea to use very complicated names for things
that are just experimental. That way noone would want to keep them ;-)

   Gee Konrad, I thought you had been playing with my matrices.  I already  

Not as much as I would like...

   easier.  One thing that I really like about slices is that you can leave off  
   the start or end points, and have them assigned appropriately for the array  
   (just as in normal python slice indexing).  This is a LOT easier to use  
   than range.

True. So how about allowing three-argument slices? Fixing the parser
is easy; implementing the feature for other sequence types is probably
some more work, but feasible. There is one semantic problem, which
also exists for your Slice() objects: how is assignment to such
generalized slices defined if the number of elements in the new-value
object doesn't match the number of elements in the slice? Assigning to
"traditional" slices simply changes the length of a sequence. Of
course there is always the possibility of raising an error, but maybe
there is some useful interpretation of this.

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From et@appl-math.tu-muenchen.de  Mon Nov 13 11:57:32 1995
From: et@appl-math.tu-muenchen.de (Thomas Schwaller)
Date: Mon, 13 Nov 1995 12:57:32 +0100
Subject: [PYTHON MATRIX-SIG] Speed...cg...and more!
Message-ID: <9511131257.ZM15259@piranha.appl-math.tu-muenchen.de>

Hi all. Unfortunately I missed the first 5 weeks or so :-( of the
very interesting but sometimes quite heavy discussion!
So let me begin slow.... ;-)

1) The ofunc object is very interesting, but I miss a feature which I always
   missed also in the mathmodule.c of the Python distribution. When I want to
   use e.g. sin(a) of an not predefined type (the new math functions in
   Matrix just extend the standard ones by comples numbers, matrices,..)
   I would like that sin (and all the other ones) test at last if
   the object has a sin attribute and execute it. In Mathmodule.c this was
   just a minor hack but here I don't now. Why do I want that behaviour.
   I write a lot of math stuff (ince contributes a 1D automatic differentiation
   module) and I also want to be able to call sin(a) of these types.
   In case of the Matrix objects one problem we will ultimately be faced with
   is the problem of using e.g. exp(A) but not in the pointwise sense
   but in the mathematical sense (defined by power series for example)
   So what to do then. Extending exp in python is done very eay:

from Matrix import *

Matrix_sin=sin

def sin(x):
	"""uses builtin sin function or attribute sin"""
	try:
		return Matrix_sin(x)
	except AttributeError:
		if hasattr(x, 'sin'): return x.sin()
		else: raise AttributeError, 'sin not available for this type'

but I think this should be in the python code, so I just can do something like

class dummy:
	def __init__(self, x)
		self.x=x

	def sin(self):
		return sin(x), sin(x-1)

a=dummy()
print sin(a)

This is a thing which should be there once and for all.


2) When writing mathematical stuff with matrices one uses very often
   the multiplication (in the Matrix sense) with transposed matrices.
   Something like:
   s  = Multiply(A.transpose(), r)

   Is it possible to write that directly with the available methods.
   When doing this kind of operation you don't really need to trnaspose
   the matrix, just switch the order of the the loops. When you do a lot of
   mulitplications with a lot of transposed matrices this is quite important.
   Please tell me when I'm missing something here. As far as I understand, at
      the moment you can influence the indices, but can you also influence the
        order of execution whitout producing a new matrix on the fly?
   As a goodie here's a simple conjugate gradient method for testing:
   (Hope it' correct!)

from Matrix import *
import sys


def cg(A, b, x=None, eps=1e-12, k=None, printer=None):
    m, n = A.shape
    if k == None: k = m*2   		# indeed much too high!
    if x == None: x, r = zeros(n,1), b
    else : r = b - Multiply(A, x)
    p = Multiply(A.transpose(), r)
    gamma = dot(p, p)
    for j in range(k):
	q = Multiply(A, p)
	alpha = gamma / dot(q, q)
	x  = x + alpha*p
	r  = r - alpha*q
	s  = Multiply(A.transpose(), r)
	gamma_new = dot(s, s)
	beta = gamma_new / gamma
	gamma = gamma_new
	if gamma[0] <= eps*eps: return x
	p = s + beta*p
	if printer: printer(x, r, s, p, q, beta, gamma)
    raise error,'cg-method diverges with %d iterations and eps = %.0e' %
(k,eps)

def cg_test():
    def pr(x, r, s, p, q, beta, gamma):
	print gamma[0]
    n =20
    b= ones(n, 1)
    for i in range(100):
	a = rand(n, n)
	a=0.5*(a+a.transpose())
	x = cg(a, b)
	sys.stdout.write('.')
	sys.stdout.flush()

cg_test()

3) As a matter of style, perhaps we should discuss how to write such things.
   I guess as soon as the matrixmodule will be in the standard distribution
   there will be a lot of matlab style writing. We should try to keep the
   procedures, classes ... as uniform as possible, so that everybody can
   rely on a certain behaviour. We want to be better than Matlab with such a
   powerfull Language as Python, don't we?

4) Last but not least I need a simple example how to use matrixobjects
   writing own extension.

   Suppose I have a method for comuting the first eigenvalue of a sqaure
matrix:

   int n=1000;
   double **a=....;
   double lambda1=first_eigenvalue(a, n);

   What is the standard way of using that in python?
   a=Matrix_(n,n)
   lambda1=first_eigenvalue(a)

   I mean how should I produce (access) a double** having a matrixobject?
   (this is not a question about how to write an extenssion, just about
    how to use the matrixobject :-))

5) Are the handouts of the mentionned talk about the matrix module available
for    all? Would be nice!

Tom



=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Mon Nov 13 13:29:33 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Mon, 13 Nov 1995 08:29:33 -0500
Subject: [PYTHON MATRIX-SIG] Speed...cg...and more!
In-Reply-To: <9511131257.ZM15259@piranha.appl-math.tu-muenchen.de> (et@appl-math.tu-muenchen.de)
Message-ID: <199511131329.IAA29436@cyclone.ERE.UMontreal.CA>


   1) The ofunc object is very interesting, but I miss a feature which I always
      missed also in the mathmodule.c of the Python distribution. When I want to
      use e.g. sin(a) of an not predefined type (the new math functions in
      Matrix just extend the standard ones by comples numbers, matrices,..)

I am working on a "general" math module that provides all the standard
functions for arbitrary objects. It calls functions from math for ints
and floats, functions from cmath for complex numbers, functions from
matrix for matrices, and looks for a method in all other objects.

Originally I wanted to do that in Python, but that turned out to
detetriorate performance drastically. The C module I am working on now
should have no noticeable overhead.

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From et@appl-math.tu-muenchen.de  Mon Nov 13 14:40:36 1995
From: et@appl-math.tu-muenchen.de (Thomas Schwaller)
Date: Mon, 13 Nov 1995 15:40:36 +0100
Subject: [PYTHON MATRIX-SIG] Speed...cg...and more!
Message-ID: <9511131540.ZM16801@piranha.appl-math.tu-muenchen.de>

Sorry for the typos in my last message. Here are some other things I forgot
there.
1) What about a Matrix constructor which can use constant values and
    functions for initailising.
    e.g.

    from math import *
    from Matrix import *

    f=lambda i, j: sin(i)*cos(j)
    a=Matrix(1000,1000, func=f)  #square 1000x1000 matrix
    b=a=Matrix_d(10,10,10, func=lambda i, j, k: sin(i)*cos(j)*exp(k)
    #10x10x10 tensor

   If we do that in the standard way it will not be fast enough. I nearly
always
   have this problem when using some procedure which need functions as input.
   I C-code it's no problem at all and after introducing it in python it's
   just to slow (e.g. minimize a function...). Imagine that the function is
   evaluated 100000 times! What to do. If we could compile simple functions
   on the fly this would be just fine. Not a general Python Compiler, but
   just a tiny one for certain things.
   Other possibility: Dynamic loading (not really acceptable for such things
   (interactivity is lost a little bit)
   Or write some new module for that type of work (Some Parser thigs!)
   The above example would go as
   b=Matrix(1000,1000, "sin(i)*cos(j)")
   or Matrix(1000,1000, "i,j->sin(i)*cos(j)")
   Comments?

Tom








=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Mon Nov 13 15:51:04 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Mon, 13 Nov 95 10:51:04 -0500
Subject: [PYTHON MATRIX-SIG] Speed...cg...and more!
References: <199511131329.IAA29436@cyclone.ERE.UMontreal.CA>
Message-ID: <9511131551.AA02186@ling-ling.lcs.mit.edu.LCS.MIT.EDU>



>    1) The ofunc object is very interesting, but I miss a feature which I always
>       missed also in the mathmodule.c of the Python distribution. When I want to
>       use e.g. sin(a) of an not predefined type (the new math functions in
>       Matrix just extend the standard ones by comples numbers, matrices,..)
>
> I am working on a "general" math module that provides all the standard
> functions for arbitrary objects. It calls functions from math for ints
> and floats, functions from cmath for complex numbers, functions from
> matrix for matrices, and looks for a method in all other objects.
>
> Originally I wanted to do that in Python, but that turned out to
> detetriorate performance drastically. The C module I am working on now
> should have no noticeable overhead.

And here I've been working on adding these very same features to my  
ofuncobjects.  I'm really think that this is the "right" place to do this,  
and then to produce a single omathmodule.c that does the right thing  
efficiently for all object types.  Let's talk off-line about this Konrad so  
we don't end up duplicating each others efforts here.

-Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Mon Nov 13 16:20:16 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Mon, 13 Nov 95 11:20:16 -0500
Subject: [PYTHON MATRIX-SIG] Speed...cg...and more!
References: <9511131257.ZM15259@piranha.appl-math.tu-muenchen.de>
Message-ID: <9511131620.AA02200@ling-ling.lcs.mit.edu.LCS.MIT.EDU>


> 1)

See my previous post.

> 2) When writing mathematical stuff with matrices one uses very often
>    the multiplication (in the Matrix sense) with transposed matrices.
>    Something like:
>    s  = Multiply(A.transpose(), r)

The current implementation of matrix multiply sucks!  I do very little  
linear algebra work, so I haven't gotten around to doing this properly yet.   
I'll bear this in mind when I do get around to doing things right.  The  
following is the current implementation of matrix multiplication.

def Multiply(a,b):
	return add.inner(multiply, a, b.transpose())

You should be able to use:
s = add.inner(multiply, A, r).transpose()

I'm sure that the extra transpose at the end will add very little overhead  
to your code (compared to the matrix multiplication itself).

Thanks for the CG code, this is exactly the sort of stuff I'd love to have  
people start building into standard libraries!

> 3) As a matter of style, perhaps we should discuss how to write such things.
>    I guess as soon as the matrixmodule will be in the standard distribution
>    there will be a lot of matlab style writing. We should try to keep the
>    procedures, classes ... as uniform as possible, so that everybody can
>    rely on a certain behaviour. We want to be better than Matlab with such a
>    powerfull Language as Python, don't we?

Good point.  I'd love to see people out there write some proposed style  
guides for matrix functions!

> 4) Last but not least I need a simple example how to use matrixobjects
>    writing own extension.

This is currently very poorly supported in the current 0.11 alpha release  
(expect this to change in later releases).  Look at matrixmodule.c  
matrix_sort() for a much more complicated example than your own.  Also,  
matrices are stored as contiguous memory blocks with a single pointer, to  
get the traditional C **, you need to generate it yourself (this too will be  
supported in a friendly way when I have time).

> 5) Are the handouts of the mentionned talk about the matrix module available
> for    all? Would be nice!

I agree!

And from your followup:

>     f=lambda i, j: sin(i)*cos(j)
>     a=Matrix(1000,1000, func=f)  #square 1000x1000 matrix

Here's how I'd do that using ofuncs

i = mrange(1000)
j = mrange(1000)
a = multiply.outer(sin(i), cos(j))

>    b=a=Matrix_d(10,10,10, func=lambda i, j, k: sin(i)*cos(j)*exp(k)
i = mrange(10)
j = mrange(10)
k = mrange(10)
a1 = multiply.outer(sin(i), cos(j)) #note, this tempory is only needed for clarity

b = a = multiply.outer(a1, exp(k))

Okay, I admit that this is uglier than you'd like, but it runs nearly as  
fast as the hand-coded C would.  It might be possible to write some sort of  
matrix constructor function that could "compile" to this ofunc form on the  
fly.

-Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Mon Nov 13 20:05:10 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Mon, 13 Nov 95 15:05:10 -0500
Subject: [PYTHON MATRIX-SIG] Matrix multiplies and syntactic nits
Message-ID: <9511132005.AA02648@ling-ling.lcs.mit.edu.LCS.MIT.EDU>


I'm working on putting out the 0.2 version of my matrix object, and I'm  
having a surprisingly hard time resolving some very silly naming issues.

1) There is a single python file currently called Matrix.py which imports  
everything you could ever want for basic functions on matrix objects.  This  
module has a similar role as Tkinter does in the Tk module system.  It  
defines functions and a number of useful constants.  Should I rename this  
module to Mx.py, or something similar so that people will be more inclined  
to use "import Mx" rather than "from Matrix import *" (which is what I use  
all the time).  This idea comes directly from Tkinter related discussions on  
the main list.

2) I have two possible ways to implement matrix multiplies:

a) a % b

I personally never need the modulo operator for matrices, and it does have  
enough of a resemblence to X to be reasonably mnemonic.  However, this  
breaks the current conceptual elegance of the system where every operator  
works on matrices (more or less) exactly the way it works on python scalars.

b) a.matrixMultiply(b)

This is the obvious solution, however it does make matrix equations  
extremely ugly to type.  Possibly an abbreviation is called for in this  
particular case?

Any opinions?

Note: There seem to be enough people with very reasonable objections to the  
idea of controlling "*" with a global variable that I don't consider this  
one of the possible solutions.

3) String representations of matrices

I'm not talking about the normally printed representation here, that's a  
major issue, not a nit.  I'm trying to decide between two string  
representations and again I just wanted some feedback.

The following are 2x3 matrices of integers.

a) Matrix_i((1,2,3),(4,5,6))

b) matrix([[1,2,3],[4,5,6]], 'i')

Opinions on which you should get with str(M)?

Thanks for the feedback - Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Mon Nov 13 20:51:13 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Mon, 13 Nov 1995 15:51:13 -0500
Subject: [PYTHON MATRIX-SIG] Matrix multiplies and syntactic nits
In-Reply-To: <9511132005.AA02648@ling-ling.lcs.mit.edu.LCS.MIT.EDU> (message from James Hugunin on Mon, 13 Nov 95 15:05:10 -0500)
Message-ID: <199511132051.PAA25492@cyclone.ERE.UMontreal.CA>


   defines functions and a number of useful constants.  Should I rename this  
   module to Mx.py, or something similar so that people will be more inclined  
   to use "import Mx" rather than "from Matrix import *" (which is what I use  

I don't see any need to do this. Anyone can always define a shorter
name by writing
  import Matrix
  Mx = Matrix
So I'd keep the "official" name understandable.

   2) I have two possible ways to implement matrix multiplies:

   a) a % b

NOOOOOOOOOO!

   enough of a resemblence to X to be reasonably mnemonic.  However, this  
   breaks the current conceptual elegance of the system where every operator  
   works on matrices (more or less) exactly the way it works on python scalars.

It's not just a matter of conceptual elegance, but of being able to
write code that works identically with matrices and scalars. And of
easily understanding what a certain piece of code does.

   b) a.matrixMultiply(b)

   This is the obvious solution, however it does make matrix equations  
   extremely ugly to type.  Possibly an abbreviation is called for in this  
   particular case?

Probably yes. But I'd still keep the long name for those who want to
write clear code.

   The following are 2x3 matrices of integers.

   a) Matrix_i((1,2,3),(4,5,6))

   b) matrix([[1,2,3],[4,5,6]], 'i')

   Opinions on which you should get with str(M)?

I'd prefer the first. In fact, I'd prefer a name like "IntMatrix"
instead of "Matrix_i". It is not at all obvious that the attached
letter indicates the type.

I don't like the second notation at all; it somehow implies that 'i'
is a string argument that could have any value. If you want a notation
that indicates the type as an argument, why not use types.IntType
instead of 'i'?

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From chris.chase@jhuapl.edu  Mon Nov 13 23:12:44 1995
From: chris.chase@jhuapl.edu (Chris Chase S1A)
Date: Mon, 13 Nov 1995 18:12:44 -0500
Subject: [PYTHON MATRIX-SIG] flattened array indexing
Message-ID: <199511132308.SAA03218@python.org>


I had suggested before that the "[]" syntax support both
multi-dimensional product indexing and flattened array indexing.
However, with the proposed

M[i,j] <-> M[(i,j)]

trying to also implement flattened indexing with the same syntax could
cause some problems.  Instead it might be better to have a separate
M.flat(i) method for flattened indexing.

I would then assume when i is a scalar M[i] is "hierarchical" indexing
like Jim Fulton has suggested (i.e. M[i] returns a one lower
dimensional array)

I assume that if M has 3 dimensions then M[1,2] would be an error for
not specifying the correct number of indexes.  A question:

M 1-dimensional.  
i = (1,2,3)

Is the following a "wrong number of indexes" error or will 1D arrays
be treated differently?

M[i] <-> M[(1,2,3)] 

Would one have to resort to:

M[(i,)] <-> M[((1,2,3))] ?

Chris Chase

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From et@appl-math.tu-muenchen.de  Thu Nov 16 13:57:24 1995
From: et@appl-math.tu-muenchen.de (Thomas Schwaller)
Date: Thu, 16 Nov 1995 14:57:24 +0100
Subject: No subject
Message-ID: <9511161457.ZM27141@piranha.appl-math.tu-muenchen.de>

Hi all,

when writing my first matrix algorithms I faced a "problem" of
"inconsistency" concerning matrices and vectors.

Suppose a naive user being used to Matlab, Scilab or octave.
He/she want's to to his/her first matrix computations:
a=Matrix([1,2,3],[2,3,4],[4,5,6])
b=ones(3)
Multiply(a,b)

Traceback (innermost last):
  File "<stdin>", line 1, in ?
  File "/home/et/Python-1.3/Lib/Matrix.py", line 114, in Multiply
    return add.inner(multiply, a, b.transpose())
Matrix.error: 1st dimension invalid

Aha he/she thinks, b ia a row vector. So let's transpose it
b=ones(3).transpose()

Traceback (innermost last):
  File "<stdin>", line 1, in ?
Matrix.error: 1st dimension invalid

So wat the hell is going on here, (s)he thinks.
So let's try

b=ones(3, 1)
Multiply(a,b)

[[6.0], [9.0], [15.0]]

Ah yes, well let's compute a dot product of b and compare it with something:

if dot(b,b) == 3.0: print 'ok'
else : print 'not ok'

not ok

Hm..
print dot(b,b)

[3.0]

Ah, I see..

if dot(b,b)[0] == 3.0: print 'ok'
else : print 'not ok'


ok


At this point our potential user who heard really hot things about the python
matrix class will probably not use it anymore.

What can we do to change his/her opinion, because WE know it's still
a very hot topic and we all love it, don't we? :-)

###   END OF THE NIGHTMARE TALE
;;;;-))

TOM










=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Thu Nov 16 14:34:26 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Thu, 16 Nov 1995 09:34:26 -0500
Subject: No subject
In-Reply-To: <9511161457.ZM27141@piranha.appl-math.tu-muenchen.de> (et@appl-math.tu-muenchen.de)
Message-ID: <199511161434.JAA21776@cyclone.ERE.UMontreal.CA>


   a=Matrix([1,2,3],[2,3,4],[4,5,6])
   b=ones(3)
   Multiply(a,b)

   Traceback (innermost last):
     File "<stdin>", line 1, in ?
     File "/home/et/Python-1.3/Lib/Matrix.py", line 114, in Multiply
       return add.inner(multiply, a, b.transpose())
   Matrix.error: 1st dimension invalid

This ought to work, but Multiply() is still a bit broken.
Try
     add.inner(multiply, a, b)
which does what you want. Multiply does the same, but first
transposes b (don't ask me why!), which produces the error
message.

   Aha he/she thinks, b ia a row vector. So let's transpose it
   b=ones(3).transpose()

This ought to work, and return b. So transpose() is also broken...

   At this point our potential user who heard really hot things about the python
   matrix class will probably not use it anymore.

At this point the matrix class is still in its early stages!
Patience...

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Thu Nov 16 16:58:15 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Thu, 16 Nov 95 11:58:15 -0500
Subject: [PYTHON MATRIX-SIG] Linear Algebra
References: <9511161457.ZM27141@piranha.appl-math.tu-muenchen.de>
Message-ID: <9511161658.AA01382@ling-ling.lcs.mit.edu.LCS.MIT.EDU>


Warning, I spend almost all of my time doing signal processing type work,  
so you should expect that the linear algebra side of my matrix object is not  
quite right.  Please keep sending these sorts of comments so that I can  
figure out what the linear algebra types want (except for * <-->  
matrixMultiply) and implement it properly.

Konrad summed up most of my response in the following lines:
> This ought to work, but Multiply() is still a bit broken.
> This ought to work, and return b. So transpose() is also broken...
> At this point the matrix class is still in its early stages!
> Patience...

I'll fix both of these for the next release (I'd been hoping for this  
evening, but Friday is looking more likely).

Keep the bug reports coming!

-Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Thu Nov 16 16:58:15 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Thu, 16 Nov 95 11:58:15 -0500
Subject: [PYTHON MATRIX-SIG] Linear Algebra
References: <9511161457.ZM27141@piranha.appl-math.tu-muenchen.de>
Message-ID: <9511161658.AA01382@ling-ling.lcs.mit.edu.LCS.MIT.EDU>


Warning, I spend almost all of my time doing signal processing type work,  
so you should expect that the linear algebra side of my matrix object is not  
quite right.  Please keep sending these sorts of comments so that I can  
figure out what the linear algebra types want (except for * <-->  
matrixMultiply) and implement it properly.

Konrad summed up most of my response in the following lines:
> This ought to work, but Multiply() is still a bit broken.
> This ought to work, and return b. So transpose() is also broken...
> At this point the matrix class is still in its early stages!
> Patience...

I'll fix both of these for the next release (I'd been hoping for this  
evening, but Friday is looking more likely).

Keep the bug reports coming!

-Jim

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From hinsenk@ere.umontreal.ca  Thu Nov 16 17:25:04 1995
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Thu, 16 Nov 1995 12:25:04 -0500
Subject: [PYTHON MATRIX-SIG] Linear Algebra
In-Reply-To: <9511161658.AA01382@ling-ling.lcs.mit.edu.LCS.MIT.EDU> (message from James Hugunin on Thu, 16 Nov 95 11:58:15 -0500)
Message-ID: <199511161725.MAA03038@cyclone.ERE.UMontreal.CA>


   quite right.  Please keep sending these sorts of comments so that I can  
   figure out what the linear algebra types want (except for * <-->  
   matrixMultiply) and implement it properly.

Let's start with something easy: transpose().
It should work for arrays of any rank and reverse the shape.

A useful addition would be an optional argument that is
a list (or tuple or array) representing a permutation of
range(len(x.shape)). That would allow an arbitrary reshuffling
of axes.

I'll send some comments on multiplication later. For now just
that: Multiply() and Dot() are really one and the same function,
if done correctly.

-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. Centre-Ville     | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------

=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From dubois@kristen.llnl.gov  Fri Nov 17 17:43:42 1995
From: dubois@kristen.llnl.gov (P. Dubois)
Date: Fri, 17 Nov 1995 09:43:42 -0800
Subject: [PYTHON MATRIX-SIG] Matrix multiplies and syntactic nits
In-Reply-To: <9511132005.AA02648@ling-ling.lcs.mit.edu.LCS.MIT.EDU> (message
 from James Hugunin on Mon, 13 Nov 95 15:05:10 -0500)
Message-ID: <9511171743.AA29337@kristen.llnl.gov>

Jim Hugunin wrote:

> The following are 2x3 matrices of integers.

> a) Matrix_i((1,2,3),(4,5,6))

> b) matrix([[1,2,3],[4,5,6]], 'i')

> Opinions on which you should get with str(M)?

I prefer Matrix_i. I would really prefer something explicit like IntegerMatrix,
CharacterMatrix, etc, with Matrix reserved as euphemism for RealMatrix or
as a "smart" constructor as I discussed before.

It turns out you just don't use this kind of constructor much anyway,
as most matrices are produced by array functions/operators, not literal lists.

In the particular case of python there is some history having to do with using
characters to represent popular types, so the present choice is reasonable
and I don't feel strongly about this.

"If it isn't an abbreviation, you don't have to remember which
abbreviation it is."

Paul


=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From jjh@mama-bear.lcs.mit.edu  Fri Nov 17 21:31:14 1995
From: jjh@mama-bear.lcs.mit.edu (James Hugunin)
Date: Fri, 17 Nov 95 16:31:14 -0500
Subject: [PYTHON MATRIX-SIG] prototype release status report
Message-ID: <9511172131.AA01814@ling-ling.lcs.mit.edu.LCS.MIT.EDU>


Just to keep people informed of the current status of the next release of
my matrix object (which I had been claiming would be ready last night).

I read Tom's message yesterday and realized that I really need to get my
matrixMultiply and transpose operators working properly ASAP.  I spent most  
of the day today crunching code to make this happen, and it's still not
quite working.  The challenge is to support APL style matrixMultiply[1,2]
(and permutations of that) to multiply an array of vectors by an array of
matrices in the proper fashion.  I should have this working sometime this
weekend and then I'll make the new release available.

Sorry to keep people waiting.

-Jim

----------

Quick preview of the most exciting things in the next release:

type coercion is implemented for matrices, ie.
Matrix_i(1,2,3)*Matrix_f(1.,2.,3.) = Matrix_f(1.,4.,9.)

matrix printing is now controlled by a callback to a user-settable python
function for prettier matrix printing.

a**b works for pow(a,b) (Thanks to Konrad)

a[1,2,3] works for  multidimensional indexing (Thanks to Konrad)

pickling matrices works

and much more.


=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From et@appl-math.tu-muenchen.de  Mon Nov 20 15:07:08 1995
From: et@appl-math.tu-muenchen.de (Thomas Schwaller)
Date: Mon, 20 Nov 1995 16:07:08 +0100
Subject: [PYTHON MATRIX-SIG] Matrix Plot module (small announcement)
Message-ID: <9511201607.ZM10265@piranha.appl-math.tu-muenchen.de>

Hi folks,
I promised to rewrite the plmodule for use with the matrixmodule.
The next message will contain the first test version of the module. This one
contains a test script and 'HOW TO BUILD' remarks. Trivial for most of us,
but nevertheless...

GENERAL REMARKS on plplot: (read also plmodule.c)

PlPlot is certainly not the last word on Plotting (somebody should
do an OpenGL plotting module!), but as a starting point it might be useful.
I like it because it has a Tk widget with it.

John Interrante and myself wrote it as the same time but he will not support it
anymore, that's why I am doing this job... :-)
I put both distributions together, but this new version is a really a new
thing.
All List inputs are now replaced by matrix inputs (Not backward compatible !)
Could have made boths inputs (matrix and python lists ) possible, but matrix
input is much faster and is the first choice here (MatLab style), so why people
should use the slower lists instead?
Further I added __doc__ strings everywhere (this where the previous C-comments
available now with python! :-))
The Input is not realy tested. At the moment it assumes that you are doing the
right thing. Comments are welcome here...
I hope I well get feedback from people using that module (which was done
quite fast, but I don't want let you wait! :-))
Send me as much scripts using that stuff (perhaps some Matlab alike procedures)
I some people want to do the missing things, you are welcome.
Mai place will be ftp://ftp.appl-math.tu-muenchen.de/pub/et/plmodule.tgz

Enjoy it...


Tom



HOW TO BUILD:

1) PLplot is available by anonymous ftp from dino.ph.utexas.edu in the
   plplot/ directory.
2) Install plplot (configure it with double precision and tk support)
   You will get a libplplotdtk.a (or build a shared library)
3) Rebuid python with Tk and add

   extern int Pltk_Init(Tcl_Interp*);

   if (Pltk_Init(interp) == TCL_ERROR)
     return TCL_ERROR;

   in tkappinit.c and

   add -lplplotdtk (+ perhaps appropriate path) in Setup at
   the right place.

3a) Build the plmodule as shared library or as built in module.

4) Add the following to your TKinter.py

class PLWin(Widget):
	def __init__(self, master=None, cnf={}, **kw):
		Widget.__init__(self, master, 'plframe', cnf, kw)

class PLXWin(Widget):
	def __init__(self, master=None, cnf={}, **kw):
		Widget.__init__(self, master, 'PLXWin', cnf, kw)


#! /usr/local/bin/python

from pl import *
from Matrix import *
from Tkinter import *

class Test:
  def plot0(self):
    pladv(0)
    plcol(1)
    plvpor(0.0, 1.0, 0.0, 1.0)
    plwind(0.0, 1.0, 0.0, 1.0)
    plbox("bc", 0.0, 0, "bc", 0.0, 0)
    plsvpa(50.0, 150.0, 100.0, 150.0)
    plwind(0.0, 1.0, 0.0, 1.0)
    plbox("bc", 0.0, 0, "bc", 0.0, 0)
    plptex(0.5, 0.5, 1.0, 0.0, 0.5, "BOX at (50,150,100,150)")
    pleop()

  def plot1(self):
    x = mrange(0.1, 6.1, 0.1)
    y = pow(x, 2)
    xs1 = zeros(6)
    ys1 = zeros(6)
    xmin, xmax = x[0], x[59]
    ymin, ymax = y[0], y[59]
    for i in range(6):
      xs1[i] = x[i * 10 + 3]
      ys1[i] = y[i * 10 + 3]
    plcol(1)
    plenv(xmin, xmax, ymin, ymax, 0, 0)
    plcol(2)
    pllab("(x)", "(y)", "#frPlot Example 1 : y=x#u2")
    plcol(9)
    plpoin(xs1, ys1, 10)
    plcol(4)
    plline(x, y)
    pleop()

  def plot2(self):
    plcol(1)
    plenv(0.0, 2*pi, -1.0, 1.0, 0, 1)
    plcol(2)
    pllab("(x)", "sin(x)", "#frPlot Example 2 : Sin Function")
    plcol(3)
    x = mrange(0, 2*pi, 2*pi/500)
    plline(x, sin(x))
    pleop()

  def plot5(self):
    n = 2047
    data = sin(mrange(0, 2*pi, 2*pi/n))
    plcol(1)
    plhist(data, -1.1, 1.1, 44, 0)
    plcol(2)
    pllab("#frValue", "#frFrequency", "#frPlot Example 5 : Probability function
of Oscillator")
    pleop()

  def plot8(self):
    m, n  =  35, 46
    x=mrange(-1, 1, 2.0/m)
    y=mrange(-1, 1, 2.0/n)
    r=sqrt(add.outer(x*x, y*y))
    z=exp(-r*r)*cos(2*pi*r)
    pladv(0)
    plvpor(0.0, 1.0, 0.0, 0.9)
    plwind(-1.0, 1.0, -0.9, 1.1)
    plcol(1)
    plw3d(1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 60.0, 120)
    plbox3('bnstu', 'x axis', 0.0, 0, 'bnstu', 'y axis', 0.0, 0, 'bcdmnstuv',
'z axis', 0.0, 0)
    plcol(2)
    plplot3d(x, y, z, 3, 0)
    plcol(3)
    plmtex('t', 1.0, 0.5, 0.5, '#frPlot Example 8 : Alt=60, Az=120')
    pleop()

  def plot9(self):
    mypltr = lambda x, y: (2.0/34 * x -1.0, 2.0/34 * y -1.0)
    nx, ny  =  35, 46
    mark, space = 1500, 1500
    clevel = Matrix(-1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0)
    x=mrange(-1, 1, 2.0/nx)
    y=mrange(-1, 1, 2.0/ny)-1.0
    z=subtract.outer(x*x, y*y)
    w=multiply.outer(2*x, y)
    plenv(-1.0, 1.0, -1.0, 1.0, 0, 0)
    plcol(2)
    plcont(z, 1, nx, 1, ny, clevel, mypltr)
    plstyl(1, mark, space)
    plcol(3)
    plcont(w, 1, nx, 1, ny, clevel, mypltr)
    plstyl(0, mark, space)
    plcol(1)
    pllab("X Coordinate", "Y Coordinate", "Streamlines of flow")
    pleop()

  def makePlotMenu(self, mBar):
    Plot = Menubutton(mBar, text='Plot', underline='0')
    Plot.pack(side='left', padx='2m')
    Plot.menu = Menu(Plot)
    Plot.menu.add('command', label='Example0', command=self.plot0)
    Plot.menu.add('command', label='Example1', command=self.plot1)
    Plot.menu.add('command', label='Example2', command=self.plot2)
    #Plot.menu.add('command', label='Example3', command=self.plot3)
    Plot.menu.add('command', label='Example5', command=self.plot5)
    Plot.menu.add('command', label='Example8', command=self.plot8)
    Plot.menu.add('command', label='Example9', command=self.plot9)
    Plot.menu.add_separator()
    Plot.menu.add('command', label='Quit', underline='0', background='red',
			           activebackground='green', command='exit')
    Plot['menu'] = Plot.menu
    return Plot

  def __init__(self, master, width=550, height=412, bg='black',
relief='raised'):
    self.mBar = Frame(master, relief=relief, bd='2')
    self.mBar.pack(side='top', fill='x')
    self.Plot = self.makePlotMenu(self.mBar)
    self.glx = PLWin(master, width=`width`, height=`height`, bg=bg)
    self.glx.pack()
    self.QUIT = Button(master, text='QUIT', fg='red', command=master.quit,
relief=relief)
    self.QUIT.pack(side='bottom', fill='both')

if __name__ == '__main__':
	root=Tk()
	test = Test(root, 600, 600, 'black', 'raised')
	root.mainloop()




=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From dubois@kristen.llnl.gov  Mon Nov 20 18:18:38 1995
From: dubois@kristen.llnl.gov (P. Dubois)
Date: Mon, 20 Nov 1995 10:18:38 -0800
Subject: [PYTHON MATRIX-SIG] Uniform Random Number Generator extension class
Message-ID: <9511201818.AA07428@kristen.llnl.gov>

On the matrix extension site I have posted URNG.tar. It has been tested with
the 0.11 version of the matrix extension.

This class supplies two modules:

URNGmodule.c
   Uniform random number generator objects can be created with either
a seed initialized from the clock or a seed supplied by the creating call.
The random number generator objects contain methods to return either a single
random number or a vector of random numbers (i.e., a Matrix of shape (n,)).
The individual generators are completely independent and do not affect the
stream produced by other generators. The generator is a Cray ranf() 
compatible generator.

Ranf.py
   This is the interface intended for users. Here is the entire text:

import URNG
import Matrix
# x=CreateGenerator(seed) creates an random number generator stream
#   seed < 0  ==>  Use the default initial seed value.
#   seed = 0  ==>  Set a "random" value for the seed from the system clock.
#   seed > 0  ==>  Set seed directly (32 bits only).
#   x.ranf() samples from that stream.
#   x.sample(n) returns a vector from that stream.
#
# ranf() returns a stream of random numbers
# random_sample(n) returns a vector of length n filled with random numbers
# random_matrix(n,m,...) returns an arbitrarily shaped matrix filled with
#                        random numbers.

CreateGenerator = URNG.CreateGenerator
standard_generator = CreateGenerator(-1)

def ranf():
	"Returns a single random number from the standard generator."
	return standard_generator.ranf()

def random_sample(n):
	"""Returns a vector of length n of random numbers 
	from the standard generator."""
	return  standard_generator.sample(n)

def random_matrix(*n):
	"""Returns a matrix with shape given by n of random numbers from 
	the standard generator."""
	if not n:
		raise 'random_matrix cannot be an empty shape'
        m = 1
	for i in n:
		m = m * i
	x = Matrix.reshape(random_sample(m),n)
        return x







=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From da@maigret.cog.brown.edu  Tue Nov 21 03:14:39 1995
From: da@maigret.cog.brown.edu (David Ascher)
Date: Mon, 20 Nov 1995 22:14:39 -0500 (EST)
Subject: [PYTHON MATRIX-SIG] Matrix Plot module (small announcement)
In-Reply-To: <9511201607.ZM10265@piranha.appl-math.tu-muenchen.de> from "Thomas Schwaller" at Nov 20, 95 04:07:08 pm
Message-ID: <199511210314.WAA07337@maigret>

>3a) Build the plmodule as shared library or as built in module.

NOTE: It is important to add the -DPL_DOUBLE flag to the plmodule line
in the Setup file.  Otherwise you'll end up w/ a module which works very
very strangely, as I found out. =)

--david


=================
MATRIX-SIG  - SIG on Matrix Math for Python

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

From et@appl-math.tu-muenchen.de  Mon Nov 27 17:30:28 1995
From: et@appl-math.tu-muenchen.de (Thomas Schwaller)
Date: Mon, 27 Nov 1995 18:30:28 +0100
Subject: [PYTHON MATRIX-SIG] plotmodule (Matrix version 0.2)
Message-ID: <9511271830.ZM22003@piranha.appl-math.tu-muenchen.de>

Hi everybody,
I'm just putting plplot0.2.tgz at the same place where the matrixmodule
is located. Inputs are now transformed to matrices if this is possible.
I really didnt test that feature up to know, because I'm just using matrices
for the moment. There's also a GIF of pltest.py running on my Linux box.
For that demo you need the Tix widget set. If you don't have it
just use the older demo I posted to the SIG, I just love this Notebook
widgets! :-) Still hoping somebody will send me some other stuff written with
the matrix- and pl-modules.

plplot0.2.tgz still isn't transferred!
If you have a faster connection to me, you can also get it at
ftp://ftp.appl-math.tu-muenchen.de/pub/et/plplot0.2.tgz

Tom


=================
MATRIX-SIG  - SIG on Matrix Math for Python

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