From da@maigret.cog.brown.edu  Tue Jan  9 16:50:12 1996
From: da@maigret.cog.brown.edu (David Ascher)
Date: Tue, 9 Jan 1996 11:50:12 -0500 (EST)
Subject: [PYTHON MATRIX-SIG] hello?
Message-ID: <199601091650.LAA22547@maigret>

I got a bounce from the list the last time I tried.  I'll try again.

Content part of mesage: How is the doc for the matrix module
progressing?  Anyone?

--david


=================
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 Jan 12 22:47:43 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 12 Jan 1996 17:47:43 -0500
Subject: [PYTHON MATRIX-SIG] Fast evaluation of numerical expressions
Message-ID: <199601122247.RAA02079@cyclone.ERE.UMontreal.CA>

The following is not directly related to matrices, but I suppose most
of us are also interested in more general numerical applications of
Python.

A frequent problem with Python code for numerical applications is
speed, and the matrix module will help only in those cases where an
algorithm can be expressed in terms of matrix operations on
sufficiently large matrices. Many applications also require
the evaluation of many "simple" expressions, i.e. functions of
scalar values or small arrays.

I have thought about possibilities to speed up such calculations
without writing a special C extension module. One idea that looks
promising to me is to write a special compiler for numerical
expressions. This compiler would generate code for a simple
(and fast) stack-based expression evaluator that would be written
in C; the compiler itself could be written in Python. The
expression evaluator would not have to deal with type checks
etc., and would know the standard mathematical functions.
It could therefore be a lot faster than the general expression
evaluator in Python. In addition, the expression compiler
could be followed by an optimizer that takes care of constant
subexpressions and other things.

The compiler could most easily be constructed by defining
a new type "compiled expression" and define the usual
functions on that type. Then a user could write something
like

  x = variable(types.FloatType, 0)
  n = variable(types.IntType, 1)
  y = variable(types.FloatType, 2)
  compiled_function = sin(x**n+y)
  print compiled_function(2.5, 3, 0.3)

The function "variable" would return an object of type "compiled
expression" that pushes the n-th argument to the evaluation stack. All
the other operations would just append their code to whatever code
they get in their arguments. Variable types could be restricted to
integers, floats, complex numbers, and arrays of these types. To
compensate the lack of control structures it would probably be
necessary to introduce a conditional function; loops would be replaced
by array operations.


Does this seem like a reasonable idea? And would anyone be willing
to collaborate on an implementation? Or does anyone have a better
idea to achieve fast expression evaluation?

-------------------------------------------------------------------------------
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 Jan 12 23:45:32 1996
From: guido@CNRI.Reston.VA.US (Guido van Rossum)
Date: Fri, 12 Jan 1996 18:45:32 -0500
Subject: [PYTHON MATRIX-SIG] Fast evaluation of numerical expressions
In-Reply-To: Your message of "Fri, 12 Jan 1996 17:47:43 EST."
 <199601122247.RAA02079@cyclone.ERE.UMontreal.CA>
References: <199601122247.RAA02079@cyclone.ERE.UMontreal.CA>
Message-ID: <199601122345.SAA23753@monty>

This sounds like a useful idea.  Please proceed.

(I particularly like the idea of using a 'variable' data type which
can be subjected to normal operations, yielding a data structure
representing the expression structure.  This could be used in a
symbolic algebra package, as well...)

--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  Sat Jan 13 14:32:56 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Sat, 13 Jan 1996 09:32:56 -0500
Subject: [PYTHON MATRIX-SIG] Fast evaluation of numerical expressions
In-Reply-To: <199601122345.SAA23753@monty> (message from Guido van Rossum on Fri, 12 Jan 1996 18:45:32 -0500)
Message-ID: <199601131432.JAA07188@cyclone.ERE.UMontreal.CA>


   This sounds like a useful idea.  Please proceed.

As soon as I find some spare time...

   (I particularly like the idea of using a 'variable' data type which
   can be subjected to normal operations, yielding a data structure
   representing the expression structure.  This could be used in a
   symbolic algebra package, as well...)

Indeed. Symbolic algebra in Python would be neat...

A nice feature of this approach is that existing code can be compiled
without modification. Any Python function foo(x) that consists of a
linear sequence of statements (no conditionals, no loops) can be
compiled as simply as

   compiled_foo = foo(variable(types.FloatType))

The tricky part will be the optimizer. I'd like to have at least
extraction of common subexpressions, which occur rather often
in numerical expressions.

-------------------------------------------------------------------------------
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@Goldilocks.LCS.MIT.EDU  Tue Jan 16 14:50:00 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Tue, 16 Jan 96 09:50:00 EST
Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
Message-ID: <9601161450.AA16343@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


Hi all.  I just got back in town from an extended Christmas vacation
(I also got married, so I had a good excuse for being gone so long).
Now that I'm back in the office again, I've been thinking that it's
about time that the matrix object made it out into beta release.

There are a few naming conventions and packaging decisions to be made
before this happens.  Below are the conventions that I propose to use.
Once this object is released in beta form I have no intention of
changing the naming conventions without a REALLY good reason, so
please let me know your opinions now.

Every name in quotes should be considered a proposed name open for
discussion.

-----

The "NumericPython" package contains the following major pieces.

1) Konrad's numeric patches to the python core (incorporated into the
working version of python by Guido) will be required and included with
the distribution.  These will be the only patches to the python core
required.
  

2) One C module that must be statically linked called "multiarraymodule.c"

Having this particular module statically linked will eliminate the
need for getting the CObject proposal working before release.

Use "PyArray_" as the name of the Matrix Object.  This is a simple
renaming of the existing "PyMatrix_".

Use "array(sequence, typecode='d')" as the default
constructor for this new C type.

This PyArray C type will not implement automatic type-coercion (unlike the
current implementation).  The reason for this is that I have decided
type-coercion is a major pain for arrays of floats (as opposed to
doubles) and I happen to use arrays of floats for most of my work.  If
somebody can give me a good suggestion for how to keep automatic
type-coercion and have Matrix_f(1,2,3)*1.2 == Matrix_f(1.2,2.4,3.6)
then I might consider changing this decision.  See later note on
Array.py for an alternative.

The include files "arrayobject.h", and "ofuncobject.h" will provide
the needed C interface to the array and optimized function objects.


3) Two dynamically linkable modules called "umathmodule.c", and "ieee_umathmodule.c"
These will both provide "universal" math support, providing the basic
functions of mathmodule, plus things like "greater" and
"booleanOr" for matrices, floats, complex, ints, and generic python
objects.

The basic "umath" will cause python exceptions in the event of an
overflow or divide-by-zero, etc. (this means it will be slow).
"ieee_umath" will not check the arguments, or the results of its
computations, and this should result in standard IEEE overflow, and
NaN values occuring in arrays as well as unpredictable modulo effects
for integer overflows.  (this will be the fast version).


4) Two python objects, "Array.py" and "Matrix.py"

Array is essentially a python binding around the underlying C type,
and this will also provide for automatic type-coercion and will
generally assume that it is only working with arrays of type long,
double, and complex double (the three types of arrays that are
equivalent to python objects).  In my initial tests of this object on
LLNL's simple benchmark, I found that the performance was only 5%
slower than using the C object directly.

Matrix will inherit almost everything from Array, however it will be
limited to 2 or fewer dimensions, and m1*m2 where m1 and m2 are
matrices will perform matrix style multiplication.  If the linear
algebra people would like, other changes can be made (ie. ~m1 ==
m1.transpose(), ...).  Based on the experiments with Array, the
performance penalty for this approach should be minimal.

In order to support these python objects (and others like them), two
special data members will be added, "__array__", and "__object__".  If
an object has the member "__array__", then the C functions that handle
matrices will attempt to retrieve the matrix from this member when
passed in a python object.  In addition, they will attempt to convert
their result to an object of class "__object__" upon return.  This
means that umath.sin(Array([0, pi/2, pi])) == Array([0.,1.,0.]).
Hopefully, this convention will allow these python objects to coexist
well with any numeric libraries.


5) A standard library "Numeric.py" which will be the standard way of
importing multiarray, Array, Matrix, umath, etc.  It will include the
inverted trig functions ("sec", "csc", "arcsec", ...) as well as most
of the standard functions currently in Matrix.py


6) Great documentation and tutorials (hopefully written by Paul
DuBois).


7) A standard test suite.


8) A new version of pickle.py which is aware of matrix objects.  This
will be suggested as a replacement for the existing pickle.py.  Matrix
objects are pickled using a binary format that is endian-aware, so
pickling a matrix object is a very efficient and portable way of both
storing them and sending them around the network.


9?) A "numericmodule.c" which contains reasonably efficient fft,
matrix inversion, convolution, random numbers, eigenvalues and
filtering functions stolen from existing C code so that the package
can be viewed as a "complete" numerical computing system?


Well, that's all I can think of for now, let me know your opinions
before I start my final burst of coding and get this thing polished up
and released.

Planned schedule:

Comments on this proposal until 1/22
Final alpha release 0.30 1/26
Massive use of release 0.30, and lots of good bug reports from users
Bugfixed alpha release 0.31 2/2
More testing, and hopefully final forms of documentation and tutorials
First beta release 1.0beta1 announced to general newsgroup 2/12

-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  Tue Jan 16 15:19:28 1996
From: guido@CNRI.Reston.VA.US (Guido van Rossum)
Date: Tue, 16 Jan 1996 10:19:28 -0500
Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
In-Reply-To: Your message of "Tue, 16 Jan 1996 09:50:00 EST."
 <9601161450.AA16343@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
References: <9601161450.AA16343@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <199601161519.KAA05252@monty>

Looks good!

No comments here, except:

> 1) Konrad's numeric patches to the python core (incorporated into the
> working version of python by Guido) will be required and included with
> the distribution.  These will be the only patches to the python core
> required.

I changed one thing in Konrad's final patches: I took out support for
'i' and 'I' to indicate imaginary constants -- you have to use 'j' or
'J'.  I don't like to offer gratuitous choices (the lower/upper case
equivalency is a C legacy that I keep for consistency with other
Python numerical constants) and I expect that engineers will whine
bitterly if I chose 'i' while mathematicians will accept 'j' without
complaints...  (Note that unless you never read code written by
someone else, you must learn both alternatives if they are both
present in the language.  This is my reason for wanting to offer only
one option -- not the savings in instruction size or cycles.)

> 2) One C module that must be statically linked called "multiarraymodule.c"
> 
> Having this particular module statically linked will eliminate the
> need for getting the CObject proposal working before release.

I do have a working version of CObject which you can use if you like.
It's up to you.

--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  Tue Jan 16 16:31:56 1996
From: jfulton@usgs.gov (Jim Fulton, U.S. Geological Survey)
Date: Tue, 16 Jan 1996 11:31:56 -0500
Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
In-Reply-To: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
 "[PYTHON MATRIX-SIG] Final matrix object renaming and packaging" (Jan 16,  9:50am)
References: <9601161450.AA16343@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <9601161131.ZM4105@dsdbqvarsa.er.usgs.gov>

On Jan 16,  9:50am, James Hugunin wrote:
> Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
>
> Hi all.  I just got back in town from an extended Christmas vacation
> (I also got married, so I had a good excuse for being gone so long).

Congradulations!

> Now that I'm back in the office again, I've been thinking that it's
> about time that the matrix object made it out into beta release.
>
> There are a few naming conventions and packaging decisions to be made
> before this happens.  Below are the conventions that I propose to use.
> Once this object is released in beta form I have no intention of
> changing the naming conventions without a REALLY good reason, so
> please let me know your opinions now.

Fair enough.

>
> Every name in quotes should be considered a proposed name open for
> discussion.
>
> -----
>
> The "NumericPython" package contains the following major pieces.
>
> 1) Konrad's numeric patches to the python core (incorporated into the
> working version of python by Guido) will be required and included with
> the distribution.  These will be the only patches to the python core
> required.
>
>
> 2) One C module that must be statically linked called "multiarraymodule.c"

By statically linked, I assume you mean statically linked into the interpreter.
Right?

> Having this particular module statically linked will eliminate the
> need for getting the CObject proposal working before release.

As Guido said, the CObject proposal is working.  I'll send it to you in a
separate note.

I finished the (very small) CObject implementation very soon after the
workshop because I feel it is important to use it for the Matrix (Numeric)
module.

I feel strongly that the Matrix module should export it's C interface
using CObjects so that modules using matrices to not require that any
of the matrix software be statically linked.  In my distribution of
Python, I statically link as little as possible to keep the
interpreter and the interpreter start-up time small.  I
plan to modify FIDL to use the CObject-exported interface.

I'd be happy to assist you with this if you wish.

>
> Use "PyArray_" as the name of the Matrix Object.  This is a simple
> renaming of the existing "PyMatrix_".
>
> Use "array(sequence, typecode='d')" as the default
> constructor for this new C type.

Is this a replacement for the existing array type?

> This PyArray C type will not implement automatic type-coercion (unlike the
> current implementation).  The reason for this is that I have decided
> type-coercion is a major pain for arrays of floats (as opposed to
> doubles) and I happen to use arrays of floats for most of my work.  If
> somebody can give me a good suggestion for how to keep automatic
> type-coercion and have Matrix_f(1,2,3)*1.2 == Matrix_f(1.2,2.4,3.6)
> then I might consider changing this decision.  See later note on
> Array.py for an alternative.
>
> The include files "arrayobject.h", and "ofuncobject.h" will provide
> the needed C interface to the array and optimized function objects.
>
>
> 3) Two dynamically linkable modules called "umathmodule.c", and
"ieee_umathmodule.c"
> These will both provide "universal" math support, providing the basic
> functions of mathmodule, plus things like "greater" and
> "booleanOr" for matrices, floats, complex, ints, and generic python
> objects.
>
> The basic "umath" will cause python exceptions in the event of an
> overflow or divide-by-zero, etc. (this means it will be slow).
> "ieee_umath" will not check the arguments, or the results of its
> computations, and this should result in standard IEEE overflow, and
> NaN values occuring in arrays as well as unpredictable modulo effects
> for integer overflows.  (this will be the fast version).
>
>
> 4) Two python objects, "Array.py" and "Matrix.py"

Are these imported by Numeric, or would the user be importing these?
Is the current built-in array module going away?  If not, then there
is a name conflict on case-insensitive file systems.  I like the idea
of having the user import Numeric and then use the
Numeric.Matrix_d(...) or Numeric.Array_f(...) rather than than
importing Matrix and Array.  Is there any reason for the user to
import Array directly?  I am strongly opposed to using "Array" unless
the "array" module goes away.

>
> Array is essentially a python binding around the underlying C type,
> and this will also provide for automatic type-coercion and will
> generally assume that it is only working with arrays of type long,
> double, and complex double (the three types of arrays that are
> equivalent to python objects).  In my initial tests of this object on
> LLNL's simple benchmark, I found that the performance was only 5%
> slower than using the C object directly.
>
> Matrix will inherit almost everything from Array, however it will be
> limited to 2 or fewer dimensions, and m1*m2 where m1 and m2 are
> matrices will perform matrix style multiplication.  If the linear
> algebra people would like, other changes can be made (ie. ~m1 ==
> m1.transpose(), ...).  Based on the experiments with Array, the
> performance penalty for this approach should be minimal.
>
> In order to support these python objects (and others like them), two
> special data members will be added, "__array__", and "__object__".  If
> an object has the member "__array__", then the C functions that handle
> matrices will attempt to retrieve the matrix from this member when
> passed in a python object.

Are we taking about python members or C structure members?  Is the
__array__ member supposed to be the C pointer to a block of memory?

> In addition, they will attempt to convert
> their result to an object of class "__object__" upon return.

Class __object__?  So __object__ is a pointer to a Python class
object?  Or is it a type code?  How does the function manage to do
this?  Presumably the function needs to call some sort of constructor
function.  How does it do this?  Is this explained in the header
files?

> This
> means that umath.sin(Array([0, pi/2, pi])) == Array([0.,1.,0.]).

OK.  This makes sense

> Hopefully, this convention will allow these python objects to coexist
> well with any numeric libraries.

Could you provide some additional details?

> 5) A standard library "Numeric.py" which will be the standard way of
> importing multiarray, Array, Matrix, umath, etc.  It will include the
> inverted trig functions ("sec", "csc", "arcsec", ...) as well as most
> of the standard functions currently in Matrix.py

So someone who wants to create a matrix object will do something like:

  import Numeric

  m=Numeric.Matrix_d(...)

Right? I like it. :-)

Did you keep a "Matrix" constructor that has a type code as an argument?

>
>
> 6) Great documentation and tutorials (hopefully written by Paul
> DuBois).

Wat cool.  Will we also get doc strings?

>
> 7) A standard test suite.
>
>
> 8) A new version of pickle.py which is aware of matrix objects.  This
> will be suggested as a replacement for the existing pickle.py.  Matrix
> objects are pickled using a binary format that is endian-aware, so
> pickling a matrix object is a very efficient and portable way of both
> storing them and sending them around the network.
>
>
> 9?) A "numericmodule.c" which contains reasonably efficient fft,
> matrix inversion, convolution, random numbers, eigenvalues and
> filtering functions stolen from existing C code so that the package
> can be viewed as a "complete" numerical computing system?
>
>
> Well, that's all I can think of for now, let me know your opinions
> before I start my final burst of coding and get this thing polished up
> and released.
>
> Planned schedule:
>
> Comments on this proposal until 1/22
> Final alpha release 0.30 1/26
> Massive use of release 0.30, and lots of good bug reports from users
> Bugfixed alpha release 0.31 2/2
> More testing, and hopefully final forms of documentation and tutorials
> First beta release 1.0beta1 announced to general newsgroup 2/12

Thanks for all the great work.

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 Jan 16 17:10:28 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 16 Jan 1996 12:10:28 -0500
Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
In-Reply-To: <9601161450.AA16343@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601161710.MAA07614@cyclone.ERE.UMontreal.CA>


   Hi all.  I just got back in town from an extended Christmas vacation
   (I also got married, so I had a good excuse for being gone so long).

Congratulations!

   1) Konrad's numeric patches to the python core (incorporated into the
   working version of python by Guido) will be required and included with
   the distribution.  These will be the only patches to the python core
   required.

There has been a slight modification in the meantime (there will be
only 'j' for imaginary constants, not 'i') and two corrections that
perhaps not everybody has received. I'll prepare a new set of patch
files for the beta release.

   This PyArray C type will not implement automatic type-coercion (unlike the
   current implementation).  The reason for this is that I have decided
   type-coercion is a major pain for arrays of floats (as opposed to
   doubles) and I happen to use arrays of floats for most of my work.  If
   somebody can give me a good suggestion for how to keep automatic
   type-coercion and have Matrix_f(1,2,3)*1.2 == Matrix_f(1.2,2.4,3.6)
   then I might consider changing this decision.  See later note on
   Array.py for an alternative.

One way to solve your "float" problem would be to write
   Matrix_f(1,2,3)*Matrix_f(1.2),
i.e. cast 1.2 explicitly to float. I don't see how you can avoid
that cast anyway; without type coercion, Matrix_f(1,2,3)*1.2 would
be an error.

I'd prefer to have type coercion everywhere for consistency.  If the
"high-level" classes Array and Matrix are really fast enough (about
which I have doubts, see below), then it doesn't matter that much, but
in general I'd give top priority to consistency and put the burden of
more complicated coding on those who want top speed (which of course
must be possible).

   3) Two dynamically linkable modules called "umathmodule.c", and "ieee_umathmodule.c"

I don't think that using "ieee" in the name is a good idea. After all,
there is no guarantee that this will really use IEEE arithmetic (a
Vax, for example, doesn't have IEEE arithmetic hardware). Why not
just "fast_umath"?

   4) Two python objects, "Array.py" and "Matrix.py"

   Array is essentially a python binding around the underlying C type,
   and this will also provide for automatic type-coercion and will
   generally assume that it is only working with arrays of type long,
   double, and complex double (the three types of arrays that are
   equivalent to python objects).  In my initial tests of this object on
   LLNL's simple benchmark, I found that the performance was only 5%
   slower than using the C object directly.

Nevertheless the Python wrapper could cause a significant overhead
for small arrays, which will also be used heavily. For example,
I am planning to change my vector class (3d vectors for geometry
etc.) to use an array of length 3 as its internal representation.
Do you have any data on the speed penalty for such small arrays?

   Matrix will inherit almost everything from Array, however it will be
   limited to 2 or fewer dimensions, and m1*m2 where m1 and m2 are
   matrices will perform matrix style multiplication.  If the linear
   algebra people would like, other changes can be made (ie. ~m1 ==
   m1.transpose(), ...).  Based on the experiments with Array, the
   performance penalty for this approach should be minimal.

I suppose some discussion will be necessary about the details of
this class, which until now didn't exist. Given that many people
seem to prefer a distinction between row and column vectors, it
would be a good idea to include separate constructors for them.

   5) A standard library "Numeric.py" which will be the standard way of
   importing multiarray, Array, Matrix, umath, etc.  It will include the
   inverted trig functions ("sec", "csc", "arcsec", ...) as well as most
   of the standard functions currently in Matrix.py

I am not sure it is a good idea to have such an all-encompassing
module. It would contain a rather arbitrary selection of things,
i.e. those which exist at the time it is introduced. I expect
that other numerical modules will appear later. So it would be
better to group things according to functions or applications.

   9?) A "numericmodule.c" which contains reasonably efficient fft,
   matrix inversion, convolution, random numbers, eigenvalues and
   filtering functions stolen from existing C code so that the package
   can be viewed as a "complete" numerical computing system?

Again this should be several modules: linear algebra, random
numbers, fft/convolution. We won't achieve anything "complete"
anyway, so let's not pretend we do.


Otherwise, your proposal sounds fine to me.

Konrad.

-------------------------------------------------------------------------------
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  Tue Jan 16 17:17:41 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 16 Jan 1996 12:17:41 -0500
Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
In-Reply-To: <9601161131.ZM4105@dsdbqvarsa.er.usgs.gov> (jfulton@usgs.gov)
Message-ID: <199601161717.MAA08000@cyclone.ERE.UMontreal.CA>


   I feel strongly that the Matrix module should export it's C interface
   using CObjects so that modules using matrices to not require that any
   of the matrix software be statically linked.  In my distribution of

I agree in principle, but that doesn't have to happen in the
first beta release.

   Are these imported by Numeric, or would the user be importing these?
   Is the current built-in array module going away?  If not, then there
   is a name conflict on case-insensitive file systems.  I like the idea

Why? The current "array" in a C module, so "import Array" will
never load it, independent of the file name conventions. Which
means that "import Array" will always obtain an external module,
and as long as ours is the only one, it hardly matters if it
is called "Array.py" or "array.py".

   importing Matrix and Array.  Is there any reason for the user to
   import Array directly?  I am strongly opposed to using "Array" unless

Certainly, e.g. if the user doesn't want anything else. Besides, as I
pointed out in my last mail, a general "Numeric" module is not such a
terrific idea.

   So someone who wants to create a matrix object will do something like:

     import Numeric

     m=Numeric.Matrix_d(...)

Speaking about constructors... I still prefer (strongly) more
meaningful names, like IntegerMatrix. Noone should be forced
to learn these silly type codes for standard applications.

-------------------------------------------------------------------------------
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@Goldilocks.LCS.MIT.EDU  Tue Jan 16 17:39:17 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Tue, 16 Jan 96 12:39:17 EST
Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
In-Reply-To: <9601161131.ZM4105@dsdbqvarsa.er.usgs.gov> (jfulton@usgs.gov)
Message-ID: <9601161739.AA19446@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


   From: "Jim Fulton, U.S. Geological Survey" <jfulton@usgs.gov>

   > 2) One C module that must be statically linked called "multiarraymodule.c"

   By statically linked, I assume you mean statically linked into the interpreter.
   Right?

   > Having this particular module statically linked will eliminate the
   > need for getting the CObject proposal working before release.

   As Guido said, the CObject proposal is working.  I'll send it to you in a
   separate note.

   I finished the (very small) CObject implementation very soon after the
   workshop because I feel it is important to use it for the Matrix (Numeric)
   module.

   I feel strongly that the Matrix module should export it's C interface
   using CObjects so that modules using matrices to not require that any
   of the matrix software be statically linked.  In my distribution of
   Python, I statically link as little as possible to keep the
   interpreter and the interpreter start-up time small.  I
   plan to modify FIDL to use the CObject-exported interface.

   I'd be happy to assist you with this if you wish.

I guess we run on faster networks at MIT, I never bother with dynamic
linking, and find that 4MB binaries launch as fast as I wish.  I'd be
more than happy to have somebody else implement the CObject interface,
but I just don't see the time it would take (including getting myself
up to speed on the vagaries of dynamic linking) is worthwhile.  If you
(Jim Fulton) want to try to add this interface, I'd be happy to help.

   >
   > Use "PyArray_" as the name of the Matrix Object.  This is a simple
   > renaming of the existing "PyMatrix_".
   >
   > Use "array(sequence, typecode='d')" as the default
   > constructor for this new C type.

   Is this a replacement for the existing array type?

I decided it was not worth the huge set of compromises that would have
been necessary to make the matrix/array object truly compatible with
the existing array object.  Still, the right name for this object
really is array.

There's no problem with using PyArray as the C name for the object
because the existing array object does not export an interface.  Also,
there's no problem with using the name "array" as a constructor
because avoiding these sorts of naming conflicts is why python has a
module system in the first place.  No existing code that imports
"arraymodule" will be broken, but hopefully people in the future will
start using the new multiarraymodule for the same tasks.

   > 4) Two python objects, "Array.py" and "Matrix.py"

   Are these imported by Numeric, or would the user be importing
these?

I plan to have everything in the basic distribution imported into a
flat name space under the Numeric module.  However, there's nothing to
stop people from importing these independently if they wish.

   Is the current built-in array module going away?  If not, then there
   is a name conflict on case-insensitive file systems.  

The array module is not going away.  I'm confused about the problem of
case-insensitive file systems, what do they do with tkintermodule and
TkInter?  If this is in fact an issue, then "Array.py" can be changed
to "UserArray.py" in the spirit of UserList, etc.  

	I like the idea
   of having the user import Numeric and then use the
   Numeric.Matrix_d(...) or Numeric.Array_f(...) rather than than
   importing Matrix and Array.  Is there any reason for the user to
   import Array directly?  I am strongly opposed to using "Array" unless
   the "array" module goes away.

I agree with all this (except the last line, which I'm willing to
conceed after you explain my tkinter question).

   > In order to support these python objects (and others like them), two
   > special data members will be added, "__array__", and "__object__".  If
   > an object has the member "__array__", then the C functions that handle
   > matrices will attempt to retrieve the matrix from this member when
   > passed in a python object.

   Are we taking about python members or C structure members?  Is the
   __array__ member supposed to be the C pointer to a block of memory?

The __array__ member is a member of a python object which is expected
to contain a python object of type array (the type created in C that
this whole thing is based on).

   > In addition, they will attempt to convert
   > their result to an object of class "__object__" upon return.

   Class __object__?  So __object__ is a pointer to a Python class
   object?

This is still a python member.  In python what it would do is call
m.__object__(new_array).  I assume that a similar thing can be done in C
(I haven't implemented this in C yet).

   > This
   > means that umath.sin(Array([0, pi/2, pi])) == Array([0.,1.,0.]).

   OK.  This makes sense

Remember that Array is a python object here, that's the trick I'm
trying to make work out.

   > Hopefully, this convention will allow these python objects to coexist
   > well with any numeric libraries.

   Could you provide some additional details?

Here's a bit of code for a unary function expecting a single PyArray
argument of type "double" of two dimensions:

	PyObject *op;	
	PyArrayObject *ap, *rp;

	TRY(PyArg_ParseTuple(args, "O", &op));
	TRY(ap = PyArray_ContiguousFromObject(op, PyArray_DOUBLE, 2, 2));

	// Do something with ap to get rp

	Py_DECREF(ap);

	return PyArray_Return(rp, op);

With the exception of the second argument to PyArray_Return, this is
the current way of writing such a chunk of code.

PyArray_ContiguousFromObject will convert any python sequence type to
an array of the appropriate type and dimensions if possible.  If the
argument is already an array of the appropriate type and dimensions,
then that array will be increfed and returned (unless its data points
to a discontiguous chunk of memory in which case it will be copied
into a new array with contiguous memory).  

The new feature that I want to add to this function is that if its
argument is a python object with the attribute "__array__", then this
function wil return the PyArrayObject contained in that attribute (if
this is indeed the case).

PyArray_Return is used because some operations wind up producing a
0-dimensional array.  These will be converted to the appropriate
python scalars on return.

The new feature that I want to add here is that if the second argument
has a "__class__" attribute, then the constructor for that class will
be used to return a new python object with the returned PyArrayObject
in its "__array__" attribute.

This is the simplest method I could come up with to get my
"sin(Array())" example to work.

   >
   > 6) Great documentation and tutorials (hopefully written by Paul
   > DuBois).

   Wat cool.  Will we also get doc strings?

doc strings are already done (probably could use some polishing, but...

-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@Goldilocks.LCS.MIT.EDU  Tue Jan 16 17:53:52 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Tue, 16 Jan 96 12:53:52 EST
Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
In-Reply-To: <199601161710.MAA07614@cyclone.ERE.UMontreal.CA> (hinsenk@ERE.UMontreal.CA)
Message-ID: <9601161753.AA19495@baribal.LCS.MIT.EDU.LCS.MIT.EDU>

   Date: Tue, 16 Jan 1996 12:10:28 -0500
   From: hinsenk@ERE.UMontreal.CA (Hinsen Konrad)

      1) Konrad's numeric patches to the python core (incorporated into the
      working version of python by Guido) will be required and included with
      the distribution.  These will be the only patches to the python core
      required.

   There has been a slight modification in the meantime (there will be
   only 'j' for imaginary constants, not 'i') and two corrections that
   perhaps not everybody has received. I'll prepare a new set of patch
   files for the beta release.

Great, just upload the patch files to "the site" when you're ready.


      This PyArray C type will not implement automatic type-coercion (unlike the
      current implementation).  The reason for this is that I have decided
      type-coercion is a major pain for arrays of floats (as opposed to
      doubles) and I happen to use arrays of floats for most of my work.  If
      somebody can give me a good suggestion for how to keep automatic
      type-coercion and have Matrix_f(1,2,3)*1.2 == Matrix_f(1.2,2.4,3.6)
      then I might consider changing this decision.  See later note on
      Array.py for an alternative.

   One way to solve your "float" problem would be to write
      Matrix_f(1,2,3)*Matrix_f(1.2),
   i.e. cast 1.2 explicitly to float. I don't see how you can avoid
   that cast anyway; without type coercion, Matrix_f(1,2,3)*1.2 would
   be an error.

I'm willing to be a little bit sloppy with some of the details of
types, and force the type of a scalar argument to correspond to the
type of the matrix.  This is essentially what I'm doing anyway when I
say Matrix_f(1.2) [Note, I'll have another post to come about
constructor function].

   I'd prefer to have type coercion everywhere for consistency.  If the
   "high-level" classes Array and Matrix are really fast enough (about
   which I have doubts, see below), then it doesn't matter that much, but
   in general I'd give top priority to consistency and put the burden of
   more complicated coding on those who want top speed (which of course
   must be possible).

We seem to just have a difference of opinion here, I'll wait and see
if more opinions come in.


      3) Two dynamically linkable modules called "umathmodule.c", and "ieee_umathmodule.c"

   I don't think that using "ieee" in the name is a good idea. After all,
   there is no guarantee that this will really use IEEE arithmetic (a
   Vax, for example, doesn't have IEEE arithmetic hardware). Why not
   just "fast_umath"?

Good point, actually I was originally considering "slow_umath" and
"fast_umath", but I knew you wouldn't like that.  So, the new proposed
name is "umath" and "fast_umath".


      4) Two python objects, "Array.py" and "Matrix.py"

      Array is essentially a python binding around the underlying C type,
      and this will also provide for automatic type-coercion and will
      generally assume that it is only working with arrays of type long,
      double, and complex double (the three types of arrays that are
      equivalent to python objects).  In my initial tests of this object on
      LLNL's simple benchmark, I found that the performance was only 5%
      slower than using the C object directly.

   Nevertheless the Python wrapper could cause a significant overhead
   for small arrays, which will also be used heavily. For example,
   I am planning to change my vector class (3d vectors for geometry
   etc.) to use an array of length 3 as its internal representation.
   Do you have any data on the speed penalty for such small arrays?

No data yet on that, if you want to send me a nice simple "real"
benchmark code for 3d vectors I'd be happy to add it to my bag of
tricks.  Right now everything is being optimized for LLNL style
physics code because they sent me such a nice benchmark to run.

      Matrix will inherit almost everything from Array, however it will be
      limited to 2 or fewer dimensions, and m1*m2 where m1 and m2 are
      matrices will perform matrix style multiplication.  If the linear
      algebra people would like, other changes can be made (ie. ~m1 ==
      m1.transpose(), ...).  Based on the experiments with Array, the
      performance penalty for this approach should be minimal.

   I suppose some discussion will be necessary about the details of
   this class, which until now didn't exist. Given that many people
   seem to prefer a distinction between row and column vectors, it
   would be a good idea to include separate constructors for them.

Now that I've brought things out into python classes, I think I'll
probably just let somebody who's into linear algebra code worry about
those sorts of refinements.

      5) A standard library "Numeric.py" which will be the standard way of
      importing multiarray, Array, Matrix, umath, etc.  It will include the
      inverted trig functions ("sec", "csc", "arcsec", ...) as well as most
      of the standard functions currently in Matrix.py

   I am not sure it is a good idea to have such an all-encompassing
   module. It would contain a rather arbitrary selection of things,
   i.e. those which exist at the time it is introduced. I expect
   that other numerical modules will appear later. So it would be
   better to group things according to functions or applications.

I disagree here.  I find that there is a certain core of
functions that are very nice to be able to grab with a single import
statement.  I would hate to have to start my typical script with
import umath, UMathMore, Matrix, Array, ArrayConstructors,
ArrayUtilities, ...



      9?) A "numericmodule.c" which contains reasonably efficient fft,
      matrix inversion, convolution, random numbers, eigenvalues and
      filtering functions stolen from existing C code so that the package
      can be viewed as a "complete" numerical computing system?

   Again this should be several modules: linear algebra, random
   numbers, fft/convolution. We won't achieve anything "complete"
   anyway, so let's not pretend we do.

You're obviously right here.  Part of what I was hoping to do with
this was to create a simple module so that people (even those without
a FORTRAN compiler) could take the inverse of a matrix in a reasonable
amount of time, and possibly to set up some sort of API, so that when
somebody does write the ultimate linear algebra module they will be
likely include a function called "inverse" so that I could then
trivially plug in this new more powerful system.


=================
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 Jan 16 18:00:45 1996
From: jfulton@usgs.gov (Jim Fulton, U.S. Geological Survey)
Date: Tue, 16 Jan 1996 13:00:45 -0500
Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
In-Reply-To: hinsenk@ERE.UMontreal.CA (Hinsen Konrad)
 "Re: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging" (Jan 16, 12:17pm)
References: <199601161717.MAA08000@cyclone.ERE.UMontreal.CA>
Message-ID: <9601161300.ZM4174@dsdbqvarsa.er.usgs.gov>

On Jan 16, 12:17pm, Hinsen Konrad wrote:
> Subject: Re: [PYTHON MATRIX-SIG] Final matrix object renaming and packagin
>
>    I feel strongly that the Matrix module should export it's C interface
>    using CObjects so that modules using matrices to not require that any
>    of the matrix software be statically linked.  In my distribution of
>
> I agree in principle, but that doesn't have to happen in the
> first beta release.

Perhaps not.  I'll put this together myself when I get the next alpha
release.

>
>    Are these imported by Numeric, or would the user be importing these?
>    Is the current built-in array module going away?  If not, then there
>    is a name conflict on case-insensitive file systems.  I like the idea
>
> Why? The current "array" in a C module, so "import Array" will
> never load it, independent of the file name conventions. Which
> means that "import Array" will always obtain an external module,
> and as long as ours is the only one, it hardly matters if it
> is called "Array.py" or "array.py".

Actually, at least in 1.2, if a C module and a Python module are in the same
directory, the C module gets loaded first.  But this will be most likely a
function of what order libraries appear in sys.path.  I just think that it
would be best to avoid this problem altogther by using a different name.

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@Goldilocks.LCS.MIT.EDU  Tue Jan 16 18:07:03 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Tue, 16 Jan 96 13:07:03 EST
Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
In-Reply-To: <199601161717.MAA08000@cyclone.ERE.UMontreal.CA> (hinsenk@ERE.UMontreal.CA)
Message-ID: <9601161807.AA19538@baribal.LCS.MIT.EDU.LCS.MIT.EDU>

   Date: Tue, 16 Jan 1996 12:17:41 -0500
   From: hinsenk@ERE.UMontreal.CA (Hinsen Konrad)

      importing Matrix and Array.  Is there any reason for the user to
      import Array directly?  I am strongly opposed to using "Array" unless

   Certainly, e.g. if the user doesn't want anything else. Besides, as I
   pointed out in my last mail, a general "Numeric" module is not such a
   terrific idea.

      So someone who wants to create a matrix object will do something like:

	import Numeric

	m=Numeric.Matrix_d(...)

   Speaking about constructors... I still prefer (strongly) more
   meaningful names, like IntegerMatrix. Noone should be forced
   to learn these silly type codes for standard applications.

Well, actually I guess I wasn't clear enough about my choice for
constructors.

The array constructor (for PyArrayObjects):

array([1,2,3], 'd') OR array([1,2,3], types.FloatType)

will both produce a 1d array of doubles.

Similarly for Arrays (and Matrix's):

Array([1,2,3], 'd') OR Array([1.,2.,3.]) OR 
Array([1,2,3], types.FloatType)

One dilemma left is what should be used as the standard string
representation of an Array (or an array).

I vote for Array([1,2,3], 'd'), but I'm open to other proposals.


Now, I happen to really like the old notation, and I'd love to come up
with a way to keep it around as a shorthand input notation.  I really
did find that the removal of a set of parenthesis made some of my
denser code a lot easier to read.

So, I propose to add A_d(1,2,3) as a convenient shorthand for
Array([1,2,3], "d").  Please, let me know how terrible an idea this is.

I'd also be happy to have FloatArray(1,2,3) instead.  If something
like this is desired, then I might even choose to use it as the
standard string representation.


-Jim


=================
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 Jan 16 18:42:37 1996
From: jfulton@usgs.gov (Jim Fulton, U.S. Geological Survey)
Date: Tue, 16 Jan 1996 13:42:37 -0500
Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
In-Reply-To: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
 "Re: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging" (Jan 16, 12:39pm)
References: <9601161739.AA19446@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <9601161342.ZM4236@dsdbqvarsa.er.usgs.gov>

On Jan 16, 12:39pm, James Hugunin wrote:
> Subject: Re: [PYTHON MATRIX-SIG] Final matrix object renaming and packagin
>
>    From: "Jim Fulton, U.S. Geological Survey" <jfulton@usgs.gov>
>
>    > 2) One C module that must be statically linked called
"multiarraymodule.c"
>
>    By statically linked, I assume you mean statically linked into the
interpreter.
>    Right?
>
>    > Having this particular module statically linked will eliminate the
>    > need for getting the CObject proposal working before release.
>
>    As Guido said, the CObject proposal is working.  I'll send it to you in a
>    separate note.
>
>    I finished the (very small) CObject implementation very soon after the
>    workshop because I feel it is important to use it for the Matrix (Numeric)
>    module.
>
>    I feel strongly that the Matrix module should export it's C interface
>    using CObjects so that modules using matrices to not require that any
>    of the matrix software be statically linked.  In my distribution of
>    Python, I statically link as little as possible to keep the
>    interpreter and the interpreter start-up time small.  I
>    plan to modify FIDL to use the CObject-exported interface.
>
>    I'd be happy to assist you with this if you wish.
>
> I guess we run on faster networks at MIT, I never bother with dynamic
> linking, and find that 4MB binaries launch as fast as I wish.

Just out of curiousity, how fast is that?  What do you get from:

  time python -c ''

On some of our slower systems, this takes about a second, even with
almost all modules dynamically loaded.  This is much slower than I'd
like it to be, since Python is often used here for very small scripts
in which this startup time is a significant part of the overall
execution time.  Starting up another version of the interpreter with
Tk linked in takes nearly twice as long.


> I'd be
> more than happy to have somebody else implement the CObject interface,
> but I just don't see the time it would take (including getting myself
> up to speed on the vagaries of dynamic linking) is worthwhile.  If you
> (Jim Fulton) want to try to add this interface, I'd be happy to help.

I'll take a crack at this when you release 0.3.

>    >
>    > Use "PyArray_" as the name of the Matrix Object.  This is a simple
>    > renaming of the existing "PyMatrix_".
>    >
>    > Use "array(sequence, typecode='d')" as the default
>    > constructor for this new C type.
>
>    Is this a replacement for the existing array type?
>
> I decided it was not worth the huge set of compromises that would have
> been necessary to make the matrix/array object truly compatible with
> the existing array object.  Still, the right name for this object
> really is array.
>
> There's no problem with using PyArray as the C name for the object
> because the existing array object does not export an interface.  Also,
> there's no problem with using the name "array" as a constructor
> because avoiding these sorts of naming conflicts is why python has a
> module system in the first place.  No existing code that imports
> "arraymodule" will be broken, but hopefully people in the future will
> start using the new multiarraymodule for the same tasks.

But existing imports of array on some systems may be broken.  Even though the
array module is stored in arraymodule._, it is imported with "import array".

>    > 4) Two python objects, "Array.py" and "Matrix.py"
>
>    Are these imported by Numeric, or would the user be importing
> these?
>
> I plan to have everything in the basic distribution imported into a
> flat name space under the Numeric module.  However, there's nothing to
> stop people from importing these independently if they wish.
>
>    Is the current built-in array module going away?  If not, then there
>    is a name conflict on case-insensitive file systems.
>
> The array module is not going away.  I'm confused about the problem of
> case-insensitive file systems, what do they do with tkintermodule and
> TkInter?

Nothing, since Tkinter doesn't work on these systems yet. :-)

> If this is in fact an issue, then "Array.py" can be changed
> to "UserArray.py" in the spirit of UserList, etc.

I think it should.

> 	I like the idea
>    of having the user import Numeric and then use the
>    Numeric.Matrix_d(...) or Numeric.Array_f(...) rather than than
>    importing Matrix and Array.  Is there any reason for the user to
>    import Array directly?  I am strongly opposed to using "Array" unless
>    the "array" module goes away.
>
> I agree with all this (except the last line, which I'm willing to
> conceed after you explain my tkinter question).

Great. ;-)

>    > In order to support these python objects (and others like them), two
>    > special data members will be added, "__array__", and "__object__".  If
>    > an object has the member "__array__", then the C functions that handle
>    > matrices will attempt to retrieve the matrix from this member when
>    > passed in a python object.
>
>    Are we taking about python members or C structure members?  Is the
>    __array__ member supposed to be the C pointer to a block of memory?
>
> The __array__ member is a member of a python object which is expected
> to contain a python object of type array (the type created in C that
> this whole thing is based on).
>
>    > In addition, they will attempt to convert
>    > their result to an object of class "__object__" upon return.
>
>    Class __object__?  So __object__ is a pointer to a Python class
>    object?
>
> This is still a python member.  In python what it would do is call
> m.__object__(new_array).  I assume that a similar thing can be done in C
> (I haven't implemented this in C yet).

And new_array is one of the new built-in array objects?

>    > This
>    > means that umath.sin(Array([0, pi/2, pi])) == Array([0.,1.,0.]).
>
>    OK.  This makes sense
>
> Remember that Array is a python object here, that's the trick I'm
> trying to make work out.

So all of this is really about being able to derive Python classes from
built-in types?  That is, you want an Array (which is an instance of a Python
class) to store it's data in an array (which is an object of type PyArrayType),
and you want functions that you pass an Array to to get at it's array.  Have I
got this right?

(BTW, you should export the actual type objects.)

>    > Hopefully, this convention will allow these python objects to coexist
>    > well with any numeric libraries.
>
>    Could you provide some additional details?
>
> Here's a bit of code for a unary function expecting a single PyArray
> argument of type "double" of two dimensions:
>
> 	PyObject *op;
> 	PyArrayObject *ap, *rp;
>
> 	TRY(PyArg_ParseTuple(args, "O", &op));
> 	TRY(ap = PyArray_ContiguousFromObject(op, PyArray_DOUBLE, 2, 2));
>
> 	// Do something with ap to get rp
>
> 	Py_DECREF(ap);
>
> 	return PyArray_Return(rp, op);
>
> With the exception of the second argument to PyArray_Return, this is
> the current way of writing such a chunk of code.
>
> PyArray_ContiguousFromObject will convert any python sequence type to
> an array of the appropriate type and dimensions if possible.  If the
> argument is already an array of the appropriate type and dimensions,
> then that array will be increfed and returned (unless its data points
> to a discontiguous chunk of memory in which case it will be copied
> into a new array with contiguous memory).
>
> The new feature that I want to add to this function is that if its
> argument is a python object with the attribute "__array__", then this
> function wil return the PyArrayObject contained in that attribute (if
> this is indeed the case).

OK.  If my statement above is right, then I understand this.

> PyArray_Return is used because some operations wind up producing a
> 0-dimensional array.  These will be converted to the appropriate
> python scalars on return.
>
> The new feature that I want to add here is that if the second argument
> has a "__class__" attribute, then the constructor for that class will

You mean __object__? (I like __class__, or maybe even
__return_constructor__ better.)

> be used to return a new python object with the returned PyArrayObject
> in its "__array__" attribute.

So PyArray_Return checks to see of op has a callable __object__ member and if
it does, returns the result of calling this member with rp as an argument.
Right?

> This is the simplest method I could come up with to get my
> "sin(Array())" example to work.

Whew.  I need to think about this.  I'm not faulting your approach, but it
feels a bit complicated.

What if you had a function with multiple arguments and you wanted the
returned object to have the same type as the arguments?  For example,
what if you wanted

  spam(some_Array, some_other_Array) to return an Array and
  spam(some_Matric, some_other_Matrix) to return a Matrix?

Would you use the first argument's __object__ or the second's?

I'll probably have more to say about this after I take some time to mull it
over.

>
>    >
>    > 6) Great documentation and tutorials (hopefully written by Paul
>    > DuBois).
>
>    Wat cool.  Will we also get doc strings?
>
> doc strings are already done (probably could use some polishing, but...

Great!

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 Jan 16 18:43:07 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 16 Jan 1996 13:43:07 -0500
Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
In-Reply-To: <9601161753.AA19495@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601161843.NAA13986@cyclone.ERE.UMontreal.CA>


   I'm willing to be a little bit sloppy with some of the details of
   types, and force the type of a scalar argument to correspond to the
   type of the matrix.  This is essentially what I'm doing anyway when I

Does that mean that in "2.5*array([1,2,3], types.Integer)" the
prefactor will be silently cast to int? That would be a most
undesirable form of automatic type conversion.

One of the principles of operation should be that scalars are
considered as arrays of rank 0. From that it follows that they can be
cast explicitly to a rank-0 array of any type (including C-float), and
there are no more type problems.

BTW, that reminds me of another old constructor debate: should
array([1,2,3]) be a rank-1 or a rank-2 array? I still propose that
all constructors should take exactly one argument, scalar or
list, and that the rank of the array depends on the nesting of the
list. And now I have another argument for this: your current
constructors don't permit the construction of rank-0 arrays.

   No data yet on that, if you want to send me a nice simple "real"
   benchmark code for 3d vectors I'd be happy to add it to my bag of

Unfortunately that doesn't exist yet...

   tricks.  Right now everything is being optimized for LLNL style
   physics code because they sent me such a nice benchmark to run.

Which is hardly a good way to ensure the general usefulness
of a program ;-)

   I disagree here.  I find that there is a certain core of
   functions that are very nice to be able to grab with a single import
   statement.  I would hate to have to start my typical script with
   import umath, UMathMore, Matrix, Array, ArrayConstructors,
   ArrayUtilities, ...

Me too. But I'd rather write this "collection" module myself,
with everything I want in it, instead of having a standard
module that doesn't meet my needs.

   You're obviously right here.  Part of what I was hoping to do with
   this was to create a simple module so that people (even those without
   a FORTRAN compiler) could take the inverse of a matrix in a reasonable
   amount of time, and possibly to set up some sort of API, so that when
   somebody does write the ultimate linear algebra module they will be
   likely include a function called "inverse" so that I could then
   trivially plug in this new more powerful system.

We should learn a lesson from the old array module: never make an
interim solution a standard module. If we now quickly hack together
some collection of "useful" routines, then people will use this
interface and have problems later when they discover that they need
something better. Of course the implementation can always be
improved, but if we define a standard interface for anything,
it should be a good one.

For linear algebra, the best solution would probably be a module based
on LAPACK, which is free and also available in C (although the Fortran
version is more efficient on most machines). I don't know if
similar good and free packages exist for other applications, but
if we can't find out, we should leave this to other people.

-------------------------------------------------------------------------------
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  Tue Jan 16 18:46:30 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 16 Jan 1996 13:46:30 -0500
Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
In-Reply-To: <9601161300.ZM4174@dsdbqvarsa.er.usgs.gov> (jfulton@usgs.gov)
Message-ID: <199601161846.NAA14142@cyclone.ERE.UMontreal.CA>


   function of what order libraries appear in sys.path.  I just think that it
   would be best to avoid this problem altogther by using a different name.

I'd rather investigate a bit more and choose a reasonable name if at
all possible. After all, we are creating an API to be used by
(hopefully ;-) millions of users, who probably don't want to dig into
Python history to find out why something called an "array" everywhere
has some strange name in Python. The compromises made necessary
by Python's strange comparison implementation are bad 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  Tue Jan 16 18:46:30 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 16 Jan 1996 13:46:30 -0500
Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
In-Reply-To: <9601161300.ZM4174@dsdbqvarsa.er.usgs.gov> (jfulton@usgs.gov)
Message-ID: <199601161846.NAA14142@cyclone.ERE.UMontreal.CA>


   function of what order libraries appear in sys.path.  I just think that it
   would be best to avoid this problem altogther by using a different name.

I'd rather investigate a bit more and choose a reasonable name if at
all possible. After all, we are creating an API to be used by
(hopefully ;-) millions of users, who probably don't want to dig into
Python history to find out why something called an "array" everywhere
has some strange name in Python. The compromises made necessary
by Python's strange comparison implementation are bad 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 jjh@Goldilocks.LCS.MIT.EDU  Tue Jan 16 19:07:25 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Tue, 16 Jan 96 14:07:25 EST
Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
In-Reply-To: <9601161342.ZM4236@dsdbqvarsa.er.usgs.gov> (jfulton@usgs.gov)
Message-ID: <9601161907.AA21369@baribal.LCS.MIT.EDU.LCS.MIT.EDU>

   From: "Jim Fulton, U.S. Geological Survey" <jfulton@usgs.gov>

   > I guess we run on faster networks at MIT, I never bother with dynamic
   > linking, and find that 4MB binaries launch as fast as I wish.

   Just out of curiousity, how fast is that?  What do you get from:

     time python -c ''

   On some of our slower systems, this takes about a second, even with
   almost all modules dynamically loaded.  This is much slower than I'd
   like it to be, since Python is often used here for very small scripts
   in which this startup time is a significant part of the overall
   execution time.  Starting up another version of the interpreter with
   Tk linked in takes nearly twice as long.

~:jjh@baribal: ls -l ~/PythonSun4/python
-rwxrwxr-x  1 jjh       3227648 Jan 16 11:09 /usr/users/jjh/PythonSun4/python*
~:jjh@baribal: time ~/PythonSun4/python -c ''
0.060u 0.060s 0:00.14 85.7% 0+234k 0+0io 0pf+0w


If you're curious about the details:

All our active files are stored on a Pentium box running a
high-performance NFS server kernel (no real operating system) this
links into the network through a 100MB/s link to a switched hub.

   > I'd be
   > more than happy to have somebody else implement the CObject interface,
   > but I just don't see the time it would take (including getting myself
   > up to speed on the vagaries of dynamic linking) is worthwhile.  If you
   > (Jim Fulton) want to try to add this interface, I'd be happy to help.

   I'll take a crack at this when you release 0.3.

Great!

   >    >
   >    > Use "PyArray_" as the name of the Matrix Object.  This is a simple
   >    > renaming of the existing "PyMatrix_".
   >    >
   >    > Use "array(sequence, typecode='d')" as the default
   >    > constructor for this new C type.
   >
   >    Is this a replacement for the existing array type?
   >
   > I decided it was not worth the huge set of compromises that would have
   > been necessary to make the matrix/array object truly compatible with
   > the existing array object.  Still, the right name for this object
   > really is array.
   >
   > There's no problem with using PyArray as the C name for the object
   > because the existing array object does not export an interface.  Also,
   > there's no problem with using the name "array" as a constructor
   > because avoiding these sorts of naming conflicts is why python has a
   > module system in the first place.  No existing code that imports
   > "arraymodule" will be broken, but hopefully people in the future will
   > start using the new multiarraymodule for the same tasks.

   But existing imports of array on some systems may be broken.  Even though the
   array module is stored in arraymodule._, it is imported with "import array".

You're talking about something else here.  In my setup you'd do something like:

from multiarray import array

this would not conflict in any way with the existing arraymodule.  Now
arguments about Array.py on systems with case-insensitive filesystems
are a different matter.

   >    > In order to support these python objects (and others like them), two
   >    > special data members will be added, "__array__", and "__object__".  If
   >    > an object has the member "__array__", then the C functions that handle
   >    > matrices will attempt to retrieve the matrix from this member when
   >    > passed in a python object.
   >
   >    Are we taking about python members or C structure members?  Is the
   >    __array__ member supposed to be the C pointer to a block of memory?
   >
   > The __array__ member is a member of a python object which is expected
   > to contain a python object of type array (the type created in C that
   > this whole thing is based on).
   >
   >    > In addition, they will attempt to convert
   >    > their result to an object of class "__object__" upon return.
   >
   >    Class __object__?  So __object__ is a pointer to a Python class
   >    object?
   >
   > This is still a python member.  In python what it would do is call
   > m.__object__(new_array).  I assume that a similar thing can be done in C
   > (I haven't implemented this in C yet).

   And new_array is one of the new built-in array objects?  Exactly.

   >    > This
   >    > means that umath.sin(Array([0, pi/2, pi])) == Array([0.,1.,0.]).
   >
   >    OK.  This makes sense
   >
   > Remember that Array is a python object here, that's the trick I'm
   > trying to make work out.

   So all of this is really about being able to derive Python classes from
   built-in types?  That is, you want an Array (which is an instance of a Python
   class) to store it's data in an array (which is an object of type PyArrayType),
   and you want functions that you pass an Array to to get at it's array.  Have I
   got this right?

Yep. In addition, I want these functions to return an Array instead of
an array.  (Even I'm beggining to doubt the value of this case-based
differentiation of names by now).

   (BTW, you should export the actual type objects.)

Of course, but this still doesn't get me the behavior I want.

   >    > Hopefully, this convention will allow these python objects to coexist
   >    > well with any numeric libraries.
   >
   >    Could you provide some additional details?
   >
   > Here's a bit of code for a unary function expecting a single PyArray
   > argument of type "double" of two dimensions:
   >
   > 	PyObject *op;
   > 	PyArrayObject *ap, *rp;
   >
   > 	TRY(PyArg_ParseTuple(args, "O", &op));
   > 	TRY(ap = PyArray_ContiguousFromObject(op, PyArray_DOUBLE, 2, 2));
   >
   > 	// Do something with ap to get rp
   >
   > 	Py_DECREF(ap);
   >
   > 	return PyArray_Return(rp, op);
   >
   > With the exception of the second argument to PyArray_Return, this is
   > the current way of writing such a chunk of code.
   >
   > PyArray_ContiguousFromObject will convert any python sequence type to
   > an array of the appropriate type and dimensions if possible.  If the
   > argument is already an array of the appropriate type and dimensions,
   > then that array will be increfed and returned (unless its data points
   > to a discontiguous chunk of memory in which case it will be copied
   > into a new array with contiguous memory).
   >
   > The new feature that I want to add to this function is that if its
   > argument is a python object with the attribute "__array__", then this
   > function wil return the PyArrayObject contained in that attribute (if
   > this is indeed the case).

   OK.  If my statement above is right, then I understand this.

   > PyArray_Return is used because some operations wind up producing a
   > 0-dimensional array.  These will be converted to the appropriate
   > python scalars on return.
   >
   > The new feature that I want to add here is that if the second argument
   > has a "__class__" attribute, then the constructor for that class will

   You mean __object__? (I like __class__, or maybe even
   __return_constructor__ better.)  

I guess I still haven't finalized the name of this yet.  I like
__return_constructor__, so I'll stick with that for now.

   > be used to return a new python object with the returned PyArrayObject
   > in its "__array__" attribute.

   So PyArray_Return checks to see of op has a callable __object__ member and if
   it does, returns the result of calling this member with rp as an argument.
   Right?

Right, except of course now it checks for a __return_constructor__ member.

   > This is the simplest method I could come up with to get my
   > "sin(Array())" example to work.

   Whew.  I need to think about this.  I'm not faulting your approach, but it
   feels a bit complicated.

   What if you had a function with multiple arguments and you wanted the
   returned object to have the same type as the arguments?  For example,
   what if you wanted

     spam(some_Array, some_other_Array) to return an Array and
     spam(some_Matric, some_other_Matrix) to return a Matrix?

   Would you use the first argument's __object__ or the second's?

If they had different __return_constructor__'s, then I'd raise an
exception.  If they were the same, or only one of them had one, then
I'd use the one that was present.

   I'll probably have more to say about this after I take some time to mull it
   over.

Please say more about this.  I'm just trying to come up with a way to
make it reasonable to subclass the array/Array object for purposes
like creating a Matrix object with as little pain as possible.

-Jim



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

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

From dubois1@llnl.gov  Tue Jan 16 19:27:31 1996
From: dubois1@llnl.gov (Paul. Dubois)
Date: Tue, 16 Jan 1996 11:27:31 -0800
Subject: [PYTHON MATRIX-SIG] Thoughts on latest messages
References: <9601161807.AA19538@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <30FBFC23.6D98@llnl.gov>

Congratulations on your marriage and best wishes to you and your wife.
We all hope you can "juggle" the matrix work in with the tasks you will
receive from The Boss.

Some thoughts on the latest messages. I think it best if I simply phrase
them as what I need to do and let you mull over how this fits with
various schemes. In what follows I use the name Thing to stand for "one
of them thar matrix objects however it turns out you name it")

a. In a C extension module, I need to create a Thing. The creation
routines you have supplied in the present release are sufficient to my
needs. 

b. Given a block of memory representing an array stored in column-major
order, I need to turn it into a Thing. Things are natively row-major but
given the current implementation I can diddle with the strides in the
Thing and it works. This means Fortran interfacing is easy. Cool. Try
not to lose this, and maybe we could make a constructor that did the
kludge officially.

c. If you want to make a Whatzit in Python that encapsulates a Thing but
adds some special semantics (say, for example, arrays whose lower index
is not 0) you can almost do it perfectly with a wrapper class but the
one thing you can't spoof is when the object is an argument to something
that expects a Thing. viz, sqrt(m). If I understood you, the idea would
be that all routines expecting a Thing would, finding that they hadn't
gotten one, try to do getattr(m, '__array__') so that objects that
wished to pretend they are Things could do so. I think this will prove
very valuable and can testify that I already ran into a case where it
would have been a nice solution for me.

Opinions:

I like the coercion properties of the current package VERY much. If you
need to do something special like keep expressions from drifting up from
float to double, then some explicit handling of scalar constants is
clearly required in either case, so I'm not persuaded anything would be
gained by undoing your good work.

About the packaging of mathematical software. A glance at the humongous
documentation for Nag or IMSL will suggest that organizing the software
into "clusters" by subject would be a good idea. In the EiffelMath
library we have clusters for ODES, probability and statistics, linear
solvers, optimization, root finding, time series analysis, etc. This
helps people find what they need and also not have to bring in too much
code just to get at a given piece.

The Thing class is very likely to get imported via 'from Thing import *'
because of the need to make the sqrt etc. work right; therefore, this
namespace should be kept minimal, with more specialized software kept in
other modules. Since it is easy to make supermodules that import sets of
other modules, one can package the facilities to suit the style of work
one does.

If it is really true that you can make a PythonThing level object that
has performance only 5% off of Thing, then that would be useful since we
could inherit from it. Especially if (c) is done.
-- 
Paul F. Dubois, L-472				(510)-422-5426
Lawrence Livermore National Laboratory		FAX (510)-423-9969
Livermore, CA 94550				dubois1@llnl.gov
Consulting: PaulDubois@aol.com

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

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

From dubois1@llnl.gov  Tue Jan 16 19:36:55 1996
From: dubois1@llnl.gov (Paul. Dubois)
Date: Tue, 16 Jan 1996 11:36:55 -0800
Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
References: <199601161846.NAA14142@cyclone.ERE.UMontreal.CA>
Message-ID: <30FBFE57.4A68@llnl.gov>

Before we get too concerned about the old "array", has anyone checked
the library and found out how many places it is used? Could the new one
be plugged in pretty easily in most places that use it now? (I suspect
so.) Could someone with access to the contributer library grep it?

While requiring users to change existing code is very undesireable, this
needs to be balanced by asking how many users, how much code, how much
trouble. In the case of a central facility like this one, it is worth a
little pain to use the right name, which surely is array.

-- 
Paul F. Dubois, L-472				(510)-422-5426
Lawrence Livermore National Laboratory		FAX (510)-423-9969
Livermore, CA 94550				dubois1@llnl.gov
Consulting: PaulDubois@aol.com

=================
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 Jan 16 20:47:50 1996
From: da@maigret.cog.brown.edu (David Ascher)
Date: Tue, 16 Jan 1996 15:47:50 -0500 (EST)
Subject: [PYTHON MATRIX-SIG] Thoughts on latest messages
In-Reply-To: <30FBFC23.6D98@llnl.gov> from "Paul. Dubois" at Jan 16, 96 11:27:31 am
Message-ID: <199601162047.PAA12207@maigret>

Paul Dubois:

>c. If you want to make a Whatzit in Python that encapsulates a Thing but
>adds some special semantics (say, for example, arrays whose lower index
>is not 0) you can almost do it perfectly with a wrapper class but the
>one thing you can't spoof is when the object is an argument to something
>that expects a Thing. viz, sqrt(m). If I understood you, the idea would
>be that all routines expecting a Thing would, finding that they hadn't
>gotten one, try to do getattr(m, '__array__') so that objects that
>wished to pretend they are Things could do so. I think this will prove
>very valuable and can testify that I already ran into a case where it
>would have been a nice solution for me.

Same here.  It's a scheme similar to that used by Brian Werkentine in
Rivet (you can call rivet functions w/ rivetobjs or with classes with a
__widget attribute which is a rivetobj).  It makes lots of things much
much simpler.

Examples that I've been thinking about are "documented matrices", (class
instances with names and properties for the various dimensions) and
"visible matrices" (class instances with state information for displayed
matrices.

--david

=================
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 Jan 16 18:52:27 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 16 Jan 1996 13:52:27 -0500
Subject: [PYTHON MATRIX-SIG] Final matrix object renaming and packaging
In-Reply-To: <9601161807.AA19538@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601161852.NAA14638@cyclone.ERE.UMontreal.CA>


   The array constructor (for PyArrayObjects):

   array([1,2,3], 'd') OR array([1,2,3], types.FloatType)

   will both produce a 1d array of doubles.

OK.

   Similarly for Arrays (and Matrix's):

   Array([1,2,3], 'd') OR Array([1.,2.,3.]) OR 
   Array([1,2,3], types.FloatType)

Also OK.

   One dilemma left is what should be used as the standard string
   representation of an Array (or an array).

   I vote for Array([1,2,3], 'd'), but I'm open to other proposals.

For the high-level arrays, I'd prefer simply Array([1,2,3])
(which is the simplest equivalent input format). For the
low-level arrays, printing the type code is probably the best
solution.

   Now, I happen to really like the old notation, and I'd love to come up
   with a way to keep it around as a shorthand input notation.  I really
   did find that the removal of a set of parenthesis made some of my
   denser code a lot easier to read.

   So, I propose to add A_d(1,2,3) as a convenient shorthand for
   Array([1,2,3], "d").  Please, let me know how terrible an idea this is.

Terrible enough for me... But do we need such abbreviations
as part of the standard modules? It would probably add to the
confusion of new users. Since it's a trivial Python definition,
without speed penalties later on, why not let everyone define
his own preferred abbreviations?

-------------------------------------------------------------------------------
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@Goldilocks.LCS.MIT.EDU  Fri Jan 19 15:43:53 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Fri, 19 Jan 96 10:43:53 EST
Subject: [PYTHON MATRIX-SIG] Finalized 0.3 interface (hopefully)
Message-ID: <9601191543.AA13543@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


Well, the comments on my previous post seem to have fallen off, so
I'll try to summarize again and see if everybody's more or less happy.

1) No argument about including Konrad's latest patches (which I now
have)

2) Naming conventions for the new module (this is new)

I think that it's important to understand the value of python's module
system in avoiding conflicts with the current array module, while
still using the name array.

The new array module will be called "multiarraymodule.c".  To use this
module I need to do the following:

import multiarray

a = multiarray.array([1,2,3])

Thus, the creation operator uses the name array (which has a different
meaning in the old arraymodule).

I will reccommend that people actually use the following style instead
to import this module:

import Numeric

a = Numeric.array([1,2,3])                  #an array of longs
b = Numeric.array([1,2,3], types.FloatType) #an array of doubles
c = Numeric.array([1,2,3], 'f')             #an array of floats 

This C type WILL continue to implement automatic type coercion, but I
reserve the right to remove it if I continue to have problems making
my floating point code work in floats instead of doubles.

I'll see how Jim Fulton's CObjects work out before making a final
decision on when to add them to the release.

An array of doubles will have the standard string representation of:

array([1,2,3], 'd')

As before, the print function is coded in python, and I encourage
people to design friendly array print functions.

3) The two math modules will be umath and fast_umath.

4) Two python object UserArray.py and Matrix.py where Matrix
inherits from UserArray.

The two special data members "__array__", and "__return_constructor__"
will be supported for python objects that want to pretend to be an
array.


5) I will have an overall library Numeric.py including what I consider
to be the basic functions desired by a numeric program.  Note: after
considering Konrad's and Paul's comments, this set of basic functions
will be kept to a minimum.

6) doc strings are still the only docs for 0.30, this should change in
BETA1

7) Test suite remains

8) pickle remains

9) "numericmodule.c" is scrapped for now

One last question on installation:

I plan to package this up as an addition to the standard python
distribution, therefore, installation will consist of adding files to
Modules, Lib, and Include.  Does this strike anybody as an
unreasonable thing to do?

-Jim

=================
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  Fri Jan 19 16:17:33 1996
From: jfulton@usgs.gov (Jim Fulton, U.S. Geological Survey)
Date: Fri, 19 Jan 1996 11:17:33 -0500
Subject: [PYTHON MATRIX-SIG] Finalized 0.3 interface (hopefully)
In-Reply-To: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
 "[PYTHON MATRIX-SIG] Finalized 0.3 interface (hopefully)" (Jan 19, 10:43am)
References: <9601191543.AA13543@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <9601191117.ZM12373@dsdbqvarsa.er.usgs.gov>

On Jan 19, 10:43am, James Hugunin wrote:
> Subject: [PYTHON MATRIX-SIG] Finalized 0.3 interface (hopefully)
>
> Well, the comments on my previous post seem to have fallen off, so
> I'll try to summarize again and see if everybody's more or less happy.

(snip)

> The two special data members "__array__", and "__return_constructor__"
> will be supported for python objects that want to pretend to be an
> array.

After thinking about this a bit, I'm quite comformable with the
__array__ member idea, because there is a precedent with __float__,
__int__, and __long__.  However, I have a *strong* opinion that
__array__ should be a member *function* that returns an instance as an
array.  This is in keeping with __float__, __long__, etc.  If a
user-defined type wants to store it's data in an array data member and
return the member, it can, but other user-defined classes may want to
compute and return array data on demand.

I would also recomment that the __array__ member function should have
an optional type code argument so that an extension that wants, say, a
double precision array can request one.

With an __array__ member function, I could, for example, immagine database
table objects that extracted their numeric data as an array on demand.
This could be quite useful.

I'm not so comfortable with the __return_constructor__ idea.  It seems
to only make sense for single-argument functions.  I have an alternate
proposal.  Suppose that certain functions allowed an optional
(keyword?) argument that provided this constructor.  So, for example,
instead of:

    bar=sin(foo)

where bar and foo are both Spams (e.g. Arrays) you would have:

    bar=sin(foo,Spam)

Now, you don't want to have to type ",Spam" everytime, not because you
don't like typing, but because you don't want the clutter, so you
define a "sin" method in Spam:

    def sin(self): return sin(self,self.class)

so then you could do:

    bar=foo.sin()

I realize that this is not quite as pretty as the first version (or is
it?), but it feels cleaner overall to me.  In the case of
multi-parameter functions, it will be clear which object (the
reciever of the message) determines the return type.

(snip)

> One last question on installation:
>
> I plan to package this up as an addition to the standard python
> distribution, therefore, installation will consist of adding files to
> Modules, Lib, and Include.  Does this strike anybody as an
> unreasonable thing to do?

For now, it's OK, but the released version should be a stand-alone module.

Jim


=================
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  Fri Jan 19 16:17:33 1996
From: jfulton@usgs.gov (Jim Fulton, U.S. Geological Survey)
Date: Fri, 19 Jan 1996 11:17:33 -0500
Subject: [PYTHON MATRIX-SIG] Finalized 0.3 interface (hopefully)
In-Reply-To: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
 "[PYTHON MATRIX-SIG] Finalized 0.3 interface (hopefully)" (Jan 19, 10:43am)
References: <9601191543.AA13543@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <9601191117.ZM12373@dsdbqvarsa.er.usgs.gov>

On Jan 19, 10:43am, James Hugunin wrote:
> Subject: [PYTHON MATRIX-SIG] Finalized 0.3 interface (hopefully)
>
> Well, the comments on my previous post seem to have fallen off, so
> I'll try to summarize again and see if everybody's more or less happy.

(snip)

> The two special data members "__array__", and "__return_constructor__"
> will be supported for python objects that want to pretend to be an
> array.

After thinking about this a bit, I'm quite comformable with the
__array__ member idea, because there is a precedent with __float__,
__int__, and __long__.  However, I have a *strong* opinion that
__array__ should be a member *function* that returns an instance as an
array.  This is in keeping with __float__, __long__, etc.  If a
user-defined type wants to store it's data in an array data member and
return the member, it can, but other user-defined classes may want to
compute and return array data on demand.

I would also recomment that the __array__ member function should have
an optional type code argument so that an extension that wants, say, a
double precision array can request one.

With an __array__ member function, I could, for example, immagine database
table objects that extracted their numeric data as an array on demand.
This could be quite useful.

I'm not so comfortable with the __return_constructor__ idea.  It seems
to only make sense for single-argument functions.  I have an alternate
proposal.  Suppose that certain functions allowed an optional
(keyword?) argument that provided this constructor.  So, for example,
instead of:

    bar=sin(foo)

where bar and foo are both Spams (e.g. Arrays) you would have:

    bar=sin(foo,Spam)

Now, you don't want to have to type ",Spam" everytime, not because you
don't like typing, but because you don't want the clutter, so you
define a "sin" method in Spam:

    def sin(self): return sin(self,self.class)

so then you could do:

    bar=foo.sin()

I realize that this is not quite as pretty as the first version (or is
it?), but it feels cleaner overall to me.  In the case of
multi-parameter functions, it will be clear which object (the
reciever of the message) determines the return type.

(snip)

> One last question on installation:
>
> I plan to package this up as an addition to the standard python
> distribution, therefore, installation will consist of adding files to
> Modules, Lib, and Include.  Does this strike anybody as an
> unreasonable thing to do?

For now, it's OK, but the released version should be a stand-alone module.

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@Goldilocks.LCS.MIT.EDU  Fri Jan 19 16:39:18 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Fri, 19 Jan 96 11:39:18 EST
Subject: [PYTHON MATRIX-SIG] Finalized 0.3 interface (hopefully)
In-Reply-To: <9601191117.ZM12373@dsdbqvarsa.er.usgs.gov> (jfulton@usgs.gov)
Message-ID: <9601191639.AA13724@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


   From: "Jim Fulton, U.S. Geological Survey" <jfulton@usgs.gov>

   > The two special data members "__array__", and "__return_constructor__"
   > will be supported for python objects that want to pretend to be an
   > array.

   After thinking about this a bit, I'm quite comformable with the
   __array__ member idea, because there is a precedent with __float__,
   __int__, and __long__.  However, I have a *strong* opinion that
   __array__ should be a member *function* that returns an instance as an
   array.  This is in keeping with __float__, __long__, etc.  If a
   user-defined type wants to store it's data in an array data member and
   return the member, it can, but other user-defined classes may want to
   compute and return array data on demand.

This makes sense.

   I would also recomment that the __array__ member function should have
   an optional type code argument so that an extension that wants, say, a
   double precision array can request one.

I don't agree with this.  I really think that the __array__ member
function should return whatever the internal array is used by the
object, and let the extension convert it as it sees fit. 

   With an __array__ member function, I could, for example, immagine database
   table objects that extracted their numeric data as an array on demand.
   This could be quite useful.

This sounds useful.

   I'm not so comfortable with the __return_constructor__ idea.  It seems
   to only make sense for single-argument functions.  I have an alternate
   proposal.  Suppose that certain functions allowed an optional
   (keyword?) argument that provided this constructor.  So, for example,
   instead of:

       bar=sin(foo)

   where bar and foo are both Spams (e.g. Arrays) you would have:

       bar=sin(foo,Spam)

   Now, you don't want to have to type ",Spam" everytime, not because you
   don't like typing, but because you don't want the clutter, so you
   define a "sin" method in Spam:

       def sin(self): return sin(self,self.class)

   so then you could do:

       bar=foo.sin()

   I realize that this is not quite as pretty as the first version (or is
   it?), but it feels cleaner overall to me.  In the case of
   multi-parameter functions, it will be clear which object (the
   reciever of the message) determines the return type.

This is actually the version that I currently have running (more or
less) it can infact be implemented entirely in python as a wrapper
around the underlying math functions.  My principle problem with this
approach is that it requires me to know about all of the available
numeric functions and define equivalents for them whenever I define a
new Spam.  This just seems unreasonable to me.

For example, let's say I make a OneIndexArray (FORTRAN style indexes
start at 1).  Obviously, I want this array to work with all of the
existing operations on arrays, and to return a OneIndexArray back.

I think that Jim F sees a problem with 

power(OneIndexArray, Matrix).

I would simply have this function call raise an exception saying that
it was called with arrays having different __return_constructor__'s.


   > One last question on installation:
   >
   > I plan to package this up as an addition to the standard python
   > distribution, therefore, installation will consist of adding files to
   > Modules, Lib, and Include.  Does this strike anybody as an
   > unreasonable thing to do?

   For now, it's OK, but the released version should be a stand-alone module.

Maybe I'll let somebody else take care of these final packaging details.

   Jim

-Jim



=================
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  Fri Jan 19 16:58:21 1996
From: jfulton@usgs.gov (Jim Fulton, U.S. Geological Survey)
Date: Fri, 19 Jan 1996 11:58:21 -0500
Subject: [PYTHON MATRIX-SIG] Finalized 0.3 interface (hopefully)
In-Reply-To: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
 "Re: [PYTHON MATRIX-SIG] Finalized 0.3 interface (hopefully)" (Jan 19, 11:39am)
References: <9601191639.AA13724@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <9601191158.ZM12402@dsdbqvarsa.er.usgs.gov>

On Jan 19, 11:39am, James Hugunin wrote:
> Subject: Re: [PYTHON MATRIX-SIG] Finalized 0.3 interface (hopefully)
>
>    From: "Jim Fulton, U.S. Geological Survey" <jfulton@usgs.gov>
>
>    > The two special data members "__array__", and "__return_constructor__"
>    > will be supported for python objects that want to pretend to be an
>    > array.
>
>    After thinking about this a bit, I'm quite comformable with the
>    __array__ member idea, because there is a precedent with __float__,
>    __int__, and __long__.  However, I have a *strong* opinion that
>    __array__ should be a member *function* that returns an instance as an
>    array.  This is in keeping with __float__, __long__, etc.  If a
>    user-defined type wants to store it's data in an array data member and
>    return the member, it can, but other user-defined classes may want to
>    compute and return array data on demand.
>
> This makes sense.
>
>    I would also recomment that the __array__ member function should have
>    an optional type code argument so that an extension that wants, say, a
>    double precision array can request one.
>
> I don't agree with this.  I really think that the __array__ member
> function should return whatever the internal array is used by the
> object, and let the extension convert it as it sees fit.

I don't feel too strongly about this second point, however,
I suspect that there could be many interesting classes that don't store their
data in arrays at all.  These will have to make some decision about what to
return and this could cause an extra array to be allocated.  Also, having these
conversion functions take a type argument is sort of symetric with the type
argument in the array constructor.

>
>    With an __array__ member function, I could, for example, immagine database
>    table objects that extracted their numeric data as an array on demand.
>    This could be quite useful.
>
> This sounds useful.
>
>    I'm not so comfortable with the __return_constructor__ idea.  It seems
>    to only make sense for single-argument functions.  I have an alternate
>    proposal.  Suppose that certain functions allowed an optional
>    (keyword?) argument that provided this constructor.  So, for example,
>    instead of:
>
>        bar=sin(foo)
>
>    where bar and foo are both Spams (e.g. Arrays) you would have:
>
>        bar=sin(foo,Spam)
>
>    Now, you don't want to have to type ",Spam" everytime, not because you
>    don't like typing, but because you don't want the clutter, so you
>    define a "sin" method in Spam:
>
>        def sin(self): return sin(self,self.class)
>
>    so then you could do:
>
>        bar=foo.sin()
>
>    I realize that this is not quite as pretty as the first version (or is
>    it?), but it feels cleaner overall to me.  In the case of
>    multi-parameter functions, it will be clear which object (the
>    reciever of the message) determines the return type.
>
> This is actually the version that I currently have running (more or
> less) it can infact be implemented entirely in python as a wrapper
> around the underlying math functions.  My principle problem with this
> approach is that it requires me to know about all of the available
> numeric functions and define equivalents for them whenever I define a
> new Spam.  This just seems unreasonable to me.
>
> For example, let's say I make a OneIndexArray (FORTRAN style indexes
> start at 1).  Obviously, I want this array to work with all of the
> existing operations on arrays, and to return a OneIndexArray back.
>
> I think that Jim F sees a problem with

Actually, I'm having more of a "gut" reaction.

>
> power(OneIndexArray, Matrix).
>
> I would simply have this function call raise an exception saying that
> it was called with arrays having different __return_constructor__'s.

I think I'd rather have this thing return an array in this case.  I guess I
think it would be better to make this explicit, like:

   OneIndexArray.power(Matrix)

or like:

   OneIndexArray(power(OneIndexArray, Matrix))


>
>    > One last question on installation:
>    >
>    > I plan to package this up as an addition to the standard python
>    > distribution, therefore, installation will consist of adding files to
>    > Modules, Lib, and Include.  Does this strike anybody as an
>    > unreasonable thing to do?
>
>    For now, it's OK, but the released version should be a stand-alone module.
>
> Maybe I'll let somebody else take care of these final packaging details.

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 Jan 19 16:58:58 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 19 Jan 1996 11:58:58 -0500
Subject: [PYTHON MATRIX-SIG] Finalized 0.3 interface (hopefully)
In-Reply-To: <9601191543.AA13543@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601191658.LAA12068@cyclone.ERE.UMontreal.CA>


   This C type WILL continue to implement automatic type coercion, but I
   reserve the right to remove it if I continue to have problems making
   my floating point code work in floats instead of doubles.

But at some point it will have to be stable!

   4) Two python object UserArray.py and Matrix.py where Matrix
   inherits from UserArray.

I wonder about the meaning of "User" in the name "UserArray".  Does it
mean "the arrays that users really want"? My first idea when seeing
such a name would be "user-defined arrays", which is not at all what
we are talking about. I still propose to explore whether it is really
definitely impossible to use the name "Array", but if that is the
case, then something like "NumericArray" would make more sense than
"UserArray".

   I plan to package this up as an addition to the standard python
   distribution, therefore, installation will consist of adding files to
   Modules, Lib, and Include.  Does this strike anybody as an
   unreasonable thing to do?

It's probably the only reasonable thing to do for now. When my patches
are part of the standard distribution (i.e. in Python 1.4), it should
be possible to package everything as a standard extension.

-------------------------------------------------------------------------------
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 Jan 19 17:03:00 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 19 Jan 1996 12:03:00 -0500
Subject: [PYTHON MATRIX-SIG] Finalized 0.3 interface (hopefully)
In-Reply-To: <9601191117.ZM12373@dsdbqvarsa.er.usgs.gov> (jfulton@usgs.gov)
Message-ID: <199601191703.MAA13454@cyclone.ERE.UMontreal.CA>


   After thinking about this a bit, I'm quite comformable with the
   __array__ member idea, because there is a precedent with __float__,
   __int__, and __long__.  However, I have a *strong* opinion that
   __array__ should be a member *function* that returns an instance as an
   array.  This is in keeping with __float__, __long__, etc.  If a
   user-defined type wants to store it's data in an array data member and
   return the member, it can, but other user-defined classes may want to
   compute and return array data on demand.

I agree that this would be better, but I worry about efficiency.
Function calls in Python are notoriously slow and should be avoided.

   Now, you don't want to have to type ",Spam" everytime, not because you
   don't like typing, but because you don't want the clutter, so you
   define a "sin" method in Spam:

       def sin(self): return sin(self,self.class)

   so then you could do:

       bar=foo.sin()

   I realize that this is not quite as pretty as the first version (or is
   it?), but it feels cleaner overall to me.  In the case of

Actually, when you import "sin" from umath, sin(foo) will automatically
be translated into foo.sin(). Again, I worry about the additional
overhead of a Python function call.

-------------------------------------------------------------------------------
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@Goldilocks.LCS.MIT.EDU  Fri Jan 19 17:36:30 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Fri, 19 Jan 96 12:36:30 EST
Subject: [PYTHON MATRIX-SIG] Finalized 0.3 interface (hopefully)
In-Reply-To: <199601191658.LAA12068@cyclone.ERE.UMontreal.CA> (hinsenk@ERE.UMontreal.CA)
Message-ID: <9601191736.AA14476@baribal.LCS.MIT.EDU.LCS.MIT.EDU>

   Date: Fri, 19 Jan 1996 11:58:58 -0500
   From: hinsenk@ERE.UMontreal.CA (Hinsen Konrad)

      This C type WILL continue to implement automatic type coercion,
      but I reserve the right to remove it if I continue to have
      problems making my floating point code work in floats instead of
      doubles.

   But at some point it will have to be stable!

I agree.  It will be stable in the BETA1 release.  I'll use release
0.30 to see how well things work for me.

      4) Two python object UserArray.py and Matrix.py where Matrix
      inherits from UserArray.

   I wonder about the meaning of "User" in the name "UserArray".  Does
   it mean "the arrays that users really want"? My first idea when
   seeing such a name would be "user-defined arrays", which is not at
   all what we are talking about. I still propose to explore whether
   it is really definitely impossible to use the name "Array", but if
   that is the case, then something like "NumericArray" would make
   more sense than "UserArray".

This is just an extension of the current UserList.py and
UserDictionary.py names in the standard python distribution to refer
to python classes that are derived from C-types.  The principle
purpose for these classes (and for UserArray as well) is to be used as
a superclass for python defined subclasses.  I don't think this
convention is too bad, so I think it's best to stay consistent.

-Jim







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

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

From dubois1@llnl.gov  Fri Jan 19 19:29:04 1996
From: dubois1@llnl.gov (Paul. Dubois)
Date: Fri, 19 Jan 1996 11:29:04 -0800
Subject: [PYTHON MATRIX-SIG] Attributes vs. methods
References: <9601191639.AA13724@baribal.LCS.MIT.EDU.LCS.MIT.EDU> <9601191158.ZM12402@dsdbqvarsa.er.usgs.gov>
Message-ID: <30FFF100.7203@llnl.gov>

Pardon in advance if this gets too pedantic; I figured the range of OOP
experience varies so I go somewhat slow. The question before the SIG is
whether, for example, it should be x.shape or x.shape().

First, speaking in abstract OOP terms, a class can have two kinds of
members, attributes and methods. The former is data, the latter is
executable. In some languages (but not all) you can tell which kind of
access is being made just by looking at it:
x.f   -- f is data
x.f() -- f is a method

(Aside: this is not a GoodThing. It forces the implementor of a class to
commit to a representation for f, ie. to decide once and for all how
clients will refer to f. For example, if f represents a certain
quantity, say pressure, a decision is made immediately as to whether f
is to be a primary state variable or whether to calculate it from
something else, like the temperature. It is better if a data attribute
is indistinguishable from the client's point of view from a function
that takes no arguments. Eiffel has this right.)

That said, one then has to ask whether a certain language allows 
statements of the form 

x.f = something

If it does, then maintaining the object as an abstract data type become
difficult. For example, we may have two attributes x and y and we want
to ensure a certain relationship always holds between them. Obviously,
if any old user can come along and assign something to x without
changing y, we have problems. Thus, in many languages that allow
assignment to x.f, books are written advising that all such f's be
hidden (private) and that a function x.f() be supplied to the users
instead. Then one worries about inlining, etc.

In Python, the situation is more complicated. There is no "private". So,
a convention has developed that if an attribute has a name beginning
with an underscore, then the warranty on the object is void if the
client assigns to it. This is a reasonable compromise in that the usual
strategy of having an f() and a set_f(value) may suffer some performance
penalty since inlining isn't going to be done, and anyway there is no
private data anyway.

Next, Python allows one to make it appear that f is an attribute even if
it is not, so that while x.f "works" there really isn't such a data
member and x.f = something would not be setting it (and may even fail,
depending on the way the class was written). However, learning about
this trick implies a level of sophistication beyond the level to be
expected in the user of an application in which Python is used as the
scripting language. Such a user is too likely to try to change the shape
of the matrix by assignment.

So, my conclusion is that if x.shape in the matrix class is an
attribute, and we don't want any user to do x.shape=something, we should
call it _shape, and supply an x.shape() for normal access. I think this
argument applies to the level intended for use by the general public. 
They need a simple, consistent set of rules to live by.
-- 
Paul F. Dubois, L-472				(510)-422-5426
Lawrence Livermore National Laboratory		FAX (510)-423-9969
Livermore, CA 94550				dubois1@llnl.gov
Consulting: PaulDubois@aol.com

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

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

From jjh@Goldilocks.LCS.MIT.EDU  Fri Jan 19 19:53:55 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Fri, 19 Jan 96 14:53:55 EST
Subject: [PYTHON MATRIX-SIG] Attributes vs. methods
In-Reply-To: <30FFF100.7203@llnl.gov> (dubois1@llnl.gov)
Message-ID: <9601191953.AA15133@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


Your last line made me realize that there is essentially a bug in the
current implementation of the matrix class (I just wasn't thinking
clearly) and this might be coloring the analysis.

> So, my conclusion is that if x.shape in the matrix class is an
> attribute, and we don't want any user to do x.shape=something, we should
> call it _shape, and supply an x.shape() for normal access.

For types written in C (as the array type is) access times between
attributes and function calls are really indistinguishable, so the
issue is whether to use x.shape() to return the current shape and
x.reshape(new_shape) to set a new one, or to use x.shape and
x.shape=new_shape instead (or maybe both).  The fact that you can't do
x.shape=new_shape in the current implementation is more an accident
than a matter of design.  It would be very easy to make this work
properly (using the set_attribute facilities of python).


Here's what I propose (after thinking about things one more time):

a.typecode, a.itemsize, a.contiguous should all become methods,
because setting these values makes no sense.

a.shape, a.real, and a.imaginary should be implemented as pseudo-data in
a self-consistent manner.  This means that I'll fix the code so that
a.shape = new_shape will work properly.

Does this sound reasonable?

-Jim

=================
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  Fri Jan 19 20:01:56 1996
From: jfulton@usgs.gov (Jim Fulton, U.S. Geological Survey)
Date: Fri, 19 Jan 1996 15:01:56 -0500
Subject: [PYTHON MATRIX-SIG] Attributes vs. methods
In-Reply-To: "Paul. Dubois" <dubois1@llnl.gov>
 "[PYTHON MATRIX-SIG] Attributes vs. methods" (Jan 19, 11:29am)
References: <9601191639.AA13724@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
 <9601191158.ZM12402@dsdbqvarsa.er.usgs.gov>
 <30FFF100.7203@llnl.gov>
Message-ID: <9601191501.ZM13147@dsdbqvarsa.er.usgs.gov>

On Jan 19, 11:29am, Paul. Dubois wrote:
> Subject: [PYTHON MATRIX-SIG] Attributes vs. methods
> Pardon in advance if this gets too pedantic; I figured the range of OOP
> experience varies so I go somewhat slow. The question before the SIG is
> whether, for example, it should be x.shape or x.shape().
>
> First, speaking in abstract OOP terms, a class can have two kinds of
> members, attributes and methods. The former is data, the latter is
> executable. In some languages (but not all) you can tell which kind of
> access is being made just by looking at it:
> x.f   -- f is data
> x.f() -- f is a method
>
> (Aside: this is not a GoodThing. It forces the implementor of a class to
> commit to a representation for f, ie. to decide once and for all how
> clients will refer to f. For example, if f represents a certain
> quantity, say pressure, a decision is made immediately as to whether f
> is to be a primary state variable or whether to calculate it from
> something else, like the temperature. It is better if a data attribute
> is indistinguishable from the client's point of view from a function
> that takes no arguments. Eiffel has this right.)
>
> That said, one then has to ask whether a certain language allows
> statements of the form
>
> x.f = something
>
> If it does, then maintaining the object as an abstract data type become
> difficult. For example, we may have two attributes x and y and we want
> to ensure a certain relationship always holds between them. Obviously,
> if any old user can come along and assign something to x without
> changing y, we have problems. Thus, in many languages that allow
> assignment to x.f, books are written advising that all such f's be
> hidden (private) and that a function x.f() be supplied to the users
> instead. Then one worries about inlining, etc.
>
> In Python, the situation is more complicated. There is no "private".

All data in built-in types is private.  Data in class instances can be made
semi-private, with some effort.  Actually, I hope that in the future there will
be alternate class types that support features such as private attributes.

> So,
> a convention has developed that if an attribute has a name beginning
> with an underscore, then the warranty on the object is void if the
> client assigns to it. This is a reasonable compromise in that the usual
> strategy of having an f() and a set_f(value) may suffer some performance
> penalty since inlining isn't going to be done, and anyway there is no
> private data anyway.
>
> Next, Python allows one to make it appear that f is an attribute even if
> it is not, so that while x.f "works" there really isn't such a data
> member and x.f = something would not be setting it (and may even fail,
> depending on the way the class was written). However, learning about
> this trick implies a level of sophistication beyond the level to be
> expected in the user of an application in which Python is used as the
> scripting language. Such a user is too likely to try to change the shape
> of the matrix by assignment.

This argument assumes that the unsophisticated user is sophisticated enough to
worry about the implementation in the first place.

> So, my conclusion is that if x.shape in the matrix class is an
> attribute, and we don't want any user to do x.shape=something, we should

I'd be inclined to think about this a little differently.  I think it is
reasonable for an interface to expose properties, where properties represent
information that you can query and set for the object, without regard to
implementation.

I'd be inclined to agree that if you don't want to allow:

  x.shape = something

then shape should probably not be modeled as an attribute, however,
these same argument might be used to say that if you can say:

  "spam"[0]

you should also able to say:

  "spam"[0]="S"

> call it _shape, and supply an x.shape() for normal access. I think this
> argument applies to the level intended for use by the general public.
> They need a simple, consistent set of rules to live by.

I'm not really disagreeing with you, but I find the idea of abstract attributes
to be interesting.

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@Goldilocks.LCS.MIT.EDU  Fri Jan 19 19:53:55 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Fri, 19 Jan 96 14:53:55 EST
Subject: [PYTHON MATRIX-SIG] Attributes vs. methods
In-Reply-To: <30FFF100.7203@llnl.gov> (dubois1@llnl.gov)
Message-ID: <9601191953.AA15133@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


Your last line made me realize that there is essentially a bug in the
current implementation of the matrix class (I just wasn't thinking
clearly) and this might be coloring the analysis.

> So, my conclusion is that if x.shape in the matrix class is an
> attribute, and we don't want any user to do x.shape=something, we should
> call it _shape, and supply an x.shape() for normal access.

For types written in C (as the array type is) access times between
attributes and function calls are really indistinguishable, so the
issue is whether to use x.shape() to return the current shape and
x.reshape(new_shape) to set a new one, or to use x.shape and
x.shape=new_shape instead (or maybe both).  The fact that you can't do
x.shape=new_shape in the current implementation is more an accident
than a matter of design.  It would be very easy to make this work
properly (using the set_attribute facilities of python).


Here's what I propose (after thinking about things one more time):

a.typecode, a.itemsize, a.contiguous should all become methods,
because setting these values makes no sense.

a.shape, a.real, and a.imaginary should be implemented as pseudo-data in
a self-consistent manner.  This means that I'll fix the code so that
a.shape = new_shape will work properly.

Does this sound reasonable?

-Jim

=================
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  Fri Jan 19 20:01:56 1996
From: jfulton@usgs.gov (Jim Fulton, U.S. Geological Survey)
Date: Fri, 19 Jan 1996 15:01:56 -0500
Subject: [PYTHON MATRIX-SIG] Attributes vs. methods
In-Reply-To: "Paul. Dubois" <dubois1@llnl.gov>
 "[PYTHON MATRIX-SIG] Attributes vs. methods" (Jan 19, 11:29am)
References: <9601191639.AA13724@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
 <9601191158.ZM12402@dsdbqvarsa.er.usgs.gov>
 <30FFF100.7203@llnl.gov>
Message-ID: <9601191501.ZM13147@dsdbqvarsa.er.usgs.gov>

On Jan 19, 11:29am, Paul. Dubois wrote:
> Subject: [PYTHON MATRIX-SIG] Attributes vs. methods
> Pardon in advance if this gets too pedantic; I figured the range of OOP
> experience varies so I go somewhat slow. The question before the SIG is
> whether, for example, it should be x.shape or x.shape().
>
> First, speaking in abstract OOP terms, a class can have two kinds of
> members, attributes and methods. The former is data, the latter is
> executable. In some languages (but not all) you can tell which kind of
> access is being made just by looking at it:
> x.f   -- f is data
> x.f() -- f is a method
>
> (Aside: this is not a GoodThing. It forces the implementor of a class to
> commit to a representation for f, ie. to decide once and for all how
> clients will refer to f. For example, if f represents a certain
> quantity, say pressure, a decision is made immediately as to whether f
> is to be a primary state variable or whether to calculate it from
> something else, like the temperature. It is better if a data attribute
> is indistinguishable from the client's point of view from a function
> that takes no arguments. Eiffel has this right.)
>
> That said, one then has to ask whether a certain language allows
> statements of the form
>
> x.f = something
>
> If it does, then maintaining the object as an abstract data type become
> difficult. For example, we may have two attributes x and y and we want
> to ensure a certain relationship always holds between them. Obviously,
> if any old user can come along and assign something to x without
> changing y, we have problems. Thus, in many languages that allow
> assignment to x.f, books are written advising that all such f's be
> hidden (private) and that a function x.f() be supplied to the users
> instead. Then one worries about inlining, etc.
>
> In Python, the situation is more complicated. There is no "private".

All data in built-in types is private.  Data in class instances can be made
semi-private, with some effort.  Actually, I hope that in the future there will
be alternate class types that support features such as private attributes.

> So,
> a convention has developed that if an attribute has a name beginning
> with an underscore, then the warranty on the object is void if the
> client assigns to it. This is a reasonable compromise in that the usual
> strategy of having an f() and a set_f(value) may suffer some performance
> penalty since inlining isn't going to be done, and anyway there is no
> private data anyway.
>
> Next, Python allows one to make it appear that f is an attribute even if
> it is not, so that while x.f "works" there really isn't such a data
> member and x.f = something would not be setting it (and may even fail,
> depending on the way the class was written). However, learning about
> this trick implies a level of sophistication beyond the level to be
> expected in the user of an application in which Python is used as the
> scripting language. Such a user is too likely to try to change the shape
> of the matrix by assignment.

This argument assumes that the unsophisticated user is sophisticated enough to
worry about the implementation in the first place.

> So, my conclusion is that if x.shape in the matrix class is an
> attribute, and we don't want any user to do x.shape=something, we should

I'd be inclined to think about this a little differently.  I think it is
reasonable for an interface to expose properties, where properties represent
information that you can query and set for the object, without regard to
implementation.

I'd be inclined to agree that if you don't want to allow:

  x.shape = something

then shape should probably not be modeled as an attribute, however,
these same argument might be used to say that if you can say:

  "spam"[0]

you should also able to say:

  "spam"[0]="S"

> call it _shape, and supply an x.shape() for normal access. I think this
> argument applies to the level intended for use by the general public.
> They need a simple, consistent set of rules to live by.

I'm not really disagreeing with you, but I find the idea of abstract attributes
to be interesting.

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 Jan 19 20:36:12 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 19 Jan 1996 15:36:12 -0500
Subject: [PYTHON MATRIX-SIG] Attributes vs. methods
In-Reply-To: <9601191953.AA15133@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601192036.PAA25872@cyclone.ERE.UMontreal.CA>


   a.typecode, a.itemsize, a.contiguous should all become methods,
   because setting these values makes no sense.

They could also be read-only attributes. BTW, setting a.typecode
does make sense, as a way of casting an array to another type.
Of course this is not the recommended style.

-------------------------------------------------------------------------------
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@Goldilocks.LCS.MIT.EDU  Fri Jan 19 21:20:44 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Fri, 19 Jan 96 16:20:44 EST
Subject: [PYTHON MATRIX-SIG] Attributes vs. methods
In-Reply-To: <199601192036.PAA25872@cyclone.ERE.UMontreal.CA> (hinsenk@ERE.UMontreal.CA)
Message-ID: <9601192120.AA15839@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


   Date: Fri, 19 Jan 1996 15:36:12 -0500
   From: hinsenk@ERE.UMontreal.CA (Hinsen Konrad)
   Cc: dubois1@llnl.gov, matrix-sig@python.org


      a.typecode, a.itemsize, a.contiguous should all become methods,
      because setting these values makes no sense.

   They could also be read-only attributes. BTW, setting a.typecode
   does make sense, as a way of casting an array to another type.
   Of course this is not the recommended style.

Unfortunately, this can not be done with the current implementation of
array objects.  Because it is possible to have arrays that are
references to the memory of another array, it is essential that
casting produce a new array rather than modify the existing one.

Right now they are read-only attributes, but I think I've come to
agree with Paul that read-only attributes are a little bit confusing.

-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 Jan 19 21:25:24 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 19 Jan 1996 16:25:24 -0500
Subject: [PYTHON MATRIX-SIG] Evaluation release of expression compiler
Message-ID: <199601192125.QAA28242@cyclone.ERE.UMontreal.CA>

For those of you who still don't know what to do during the weekend, I
offer a nice toy. In the next message, I will send the source code for
the very first incomplete, non-optimized version of my numerical
expression compiler. It is a single C extension module called
"numexprmodule.c". For now, both this module and the module "cmath"
must be statically linked with the interpreter, since numexpr calls
functions from cmath.

Here's an example for an application:

--------------------------------------------------
from numexpr import *
from omath import *

def f(x):
    return sin(x*x)+0.5*sqrt(x/7)*cos(2/x)*log(x+exp(-x))-sqrt(2)*tanh(x)

f_compiled = f(FloatVariable())

print f(5)
print f_compiled(5)
--------------------------------------------------

The module "numexpr" exports three functions: IntegerVariable,
FloatVariable, and ComplexVariable. Each of these takes an
optional argument (default is zero) that indicates
the position of this variable in the argument list of the
compiled expression. So if you want a compiled expression
for "x+y", write

  f = FloatVariable(0)+FloatVariable(1)

The range of mathematical functions is the same as for cmath. All
arithmetic operators are supported, with exception of exponentiation,
which with the current coercion scheme cannot be implemented
efficiently, so I decided to wait a bit. With that restriction, all
functions that contain no conditional or loop statements can be
compiled.

Speed: First tests have shown that the asymptotic speed (i.e.  for
infinitely long functions) relative to uncompiled functions is about
40. For one-line expressions such as the one in the example above,
expect a factor of 7 (which shows that the overhead if the interpreter
is still substantial). Note that the expressions are not optimized
in any way. If you compile something like
    temp = sin(x+y)
    f = temp*temp,
then sin(x+y) will actually be calculated twice at execution time.  So
elimination of common subexpressions is the very least amount of
optimization that will have to be done.

To do:
- Control structures
- Optimization
- Array expressions

I'd appreciate any comments whatsoever.

-------------------------------------------------------------------------------
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 Jan 19 21:25:48 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 19 Jan 1996 16:25:48 -0500
Subject: [PYTHON MATRIX-SIG] numexprmodule.c
Message-ID: <199601192125.QAA28264@cyclone.ERE.UMontreal.CA>

/* Numexpr objects */

#include "allobjects.h"
#include <math.h>

/* Type of stack entries */

typedef union { long i; double f; complex c; } stack_entry;

/* Error object */

static PyObject *ErrorObject;

/* Object definition */

typedef struct {
	PyObject_HEAD
	int   nargs;		/* number of parameters */
	char *argtypes;		/* types of parameters */
	stack_entry *args;	/* array to store actual arguments */
	int   nconstants;	/* number of constants */
	stack_entry *constants;	/* constant array */
	int   codesize;		/* number of code words */
	int  *code;		/* compiled expression */
	int   stacksize;	/* stack size needed for evaluation */
	stack_entry *stack;	/* execution stack */
	char  type;		/* return type of the expression */
} PyNumExprObject;

staticforward PyTypeObject PyNumExpr_Type;

#define PyNumExpr_Check(v)  	((v)->ob_type == &PyNumExpr_Type)

/* Type codes */

#define INTEGER		1
#define FLOAT		2
#define COMPLEX		3
#define NTYPES		4

/* Opcodes used in compiled code */

#define GET_ARG		1
#define GET_CONSTANT	2
#define ADD		10
#define ADD_INT		11
#define ADD_FLOAT	12
#define ADD_COMPLEX	13
#define SUB		15
#define SUB_INT		16
#define SUB_FLOAT	17
#define SUB_COMPLEX	18
#define MUL		20
#define MUL_INT		21
#define MUL_FLOAT	22
#define MUL_COMPLEX	23
#define DIV		25
#define DIV_INT		26
#define DIV_FLOAT	27
#define DIV_COMPLEX	28
#define POW		30
#define NEG		40
#define NEG_INT		41
#define NEG_FLOAT	42
#define NEG_COMPLEX	43
#define ABS		45
#define ABS_INT		46
#define ABS_FLOAT	47
#define ABS_COMPLEX	48
#define TYPE_CAST	50
#define	INTEGER_FLOAT	59
#define	INTEGER_COMPLEX	63
#define FLOAT_INTEGER	56
#define FLOAT_COMPLEX	64
#define COMPLEX_INTEGER 57
#define COMPLEX_FLOAT   61

#define ACOS_FLOAT	100
#define ACOS_COMPLEX	101
#define ACOSH_FLOAT	102
#define ACOSH_COMPLEX	103
#define ASIN_FLOAT	104
#define ASIN_COMPLEX	105
#define ASINH_FLOAT	106
#define ASINH_COMPLEX	107
#define ATAN_FLOAT	108
#define ATAN_COMPLEX	109
#define ATANH_FLOAT	110
#define ATANH_COMPLEX	111
#define COS_FLOAT	112
#define COS_COMPLEX	113
#define COSH_FLOAT	114
#define COSH_COMPLEX	115
#define EXP_FLOAT	116
#define EXP_COMPLEX	117
#define LOG_FLOAT	118
#define LOG_COMPLEX	119
#define LOG10_FLOAT	120
#define LOG10_COMPLEX	121
#define SIN_FLOAT	122
#define SIN_COMPLEX	123
#define SINH_FLOAT	124
#define SINH_COMPLEX	125
#define SQRT_FLOAT	126
#define SQRT_COMPLEX	127
#define TAN_FLOAT	128
#define TAN_COMPLEX	129
#define TANH_FLOAT	130
#define TANH_COMPLEX	131


/* Utility functions */

#define max(a,b)	(((a) > (b)) ? (a) : (b))
#define min(a,b)	(((a) < (b)) ? (a) : (b))


/* Allocation and deallocation of numexpr objects */

static PyNumExprObject *
new_numexprobject()
{
	PyNumExprObject *self;
	self = NEWOBJ(PyNumExprObject, &PyNumExpr_Type);
	if (self == NULL)
		return NULL;
	self->nargs = 0;
	self->argtypes = NULL;
	self->args = NULL;
	self->nconstants = 0;
	self->constants = NULL;
	self->codesize = 0;
	self->code = NULL;
	self->stacksize = 0;
	self->stack = NULL;
	self->type = 0;
	return self;
}

static void
numexpr_dealloc(self)
	PyNumExprObject *self;
{
	PyMem_XDEL(self->argtypes);
	PyMem_XDEL(self->args);
	PyMem_XDEL(self->constants);
	PyMem_XDEL(self->code);
	PyMem_XDEL(self->stack);
	PyMem_DEL(self);
}

/* Attribute access. The only attributes are methods. */

struct PyMethodDef numexpr_methods[];

static PyObject *
numexpr_getattr(self, name)
	PyNumExprObject *self;
	char *name;
{
	return Py_FindMethod(numexpr_methods, (PyObject *)self, name);
}

/* Printed representation */

static PyObject *
numexpr_repr(self)
	PyNumExprObject *self;
{
	char buf[100];
	sprintf(buf, "<compiled expression (%s)>",
			self->argtypes);
	return PyString_FromString(buf);
}

/* Evaluation of a compiled expression */

extern complex c_sqrt();
extern complex c_acos();
extern complex c_acosh();
extern complex c_asin();
extern complex c_asinh();
extern complex c_atan();
extern complex c_atanh();
extern complex c_cos();
extern complex c_cosh();
extern complex c_exp();
extern complex c_log();
extern complex c_log10();
extern complex c_sin();
extern complex c_sinh();
extern complex c_sqrt();
extern complex c_tan();
extern complex c_tanh();

static PyObject *
numexpr_call(self, args)
	PyNumExprObject *self;
	PyObject *args;
{
	stack_entry *stack = self->stack;
	int *cp, *end;
	char text[50];
	stack_entry *sp;
	PyObject *arg;
	char argtype[2];
	PyObject *result;
	int i;

	if (PyObject_Length(args) != self->nargs) {
		PyErr_SetString(TypeError,
			"wrong number of arguments in compiled expression");
		return NULL;
	}
	argtype[1] = '\0';
	for (i = 0; i < self->nargs; i++)
	{
		arg = PySequence_GetItem(args, i);
		argtype[0] = self->argtypes[i];
		if (argtype[0] == ' ')
			PyArg_Parse(arg, "O", &arg);
		else
			PyArg_Parse(arg, argtype, self->args+i);
	}

	end = self->code + self->codesize;
	cp = self->code;
	sp = stack-1;
	while (cp < end) {
		switch (*cp) {

		case GET_ARG:
			cp++;
			*++sp = self->args[*cp];
			break;
		case GET_CONSTANT:
			cp++;
			*++sp = self->constants[*cp];
			break;

		case ADD_INT:
			sp[-1].i += sp[0].i;
			sp--;
			break;
		case ADD_FLOAT:
			sp[-1].f += sp[0].f;
			sp--;
			break;
		case ADD_COMPLEX:
			sp[-1].c.real += sp[0].c.real;
			sp[-1].c.imag += sp[0].c.imag;
			sp--;
			break;

		case SUB_INT:
			sp[-1].i -= sp[0].i;
			sp--;
			break;
		case SUB_FLOAT:
			sp[-1].f -= sp[0].f;
			sp--;
			break;
		case SUB_COMPLEX:
			sp[-1].c.real -= sp[0].c.real;
			sp[-1].c.imag -= sp[0].c.imag;
			sp--;
			break;

		case MUL_INT:
			sp[-1].i *= sp[0].i;
			sp--;
			break;
		case MUL_FLOAT:
			sp[-1].f *= sp[0].f;
			sp--;
			break;
		case MUL_COMPLEX:
			sp[-1].c = c_prod(sp[-1].c, sp[0].c);
			sp--;
			break;

		case DIV_INT:
			sp[-1].i /= sp[0].i;
			sp--;
			break;
		case DIV_FLOAT:
			sp[-1].f /= sp[0].f;
			sp--;
			break;
		case DIV_COMPLEX:
			sp[-1].c = c_quot(sp[-1].c, sp[0].c);
			sp--;
			break;

		case INTEGER_FLOAT:
			sp->f = sp->i;
			break;
		case INTEGER_COMPLEX:
			sp->c.real = sp->i;
			sp->c.imag = 0.;
			break;
		case FLOAT_INTEGER:
			sp->i = sp->f;
			break;
		case FLOAT_COMPLEX:
			sp->c.real = sp->f;
			sp->c.imag = 0.;
			break;
		case COMPLEX_INTEGER:
			sp->i = sp->c.real;
			break;
		case COMPLEX_FLOAT:
			sp->f = sp->c.real;
			break;

		case NEG_INT:
			sp->i = -sp->i;
			break;
		case NEG_FLOAT:
			sp->f = -sp->f;
			break;
		case NEG_COMPLEX:
			sp->c.real = -sp->c.real;
			sp->c.imag = -sp->c.imag;
			break;

		case ABS_INT:
			if (sp->i < 0)
				sp->i = -sp->i;
			break;
		case ABS_FLOAT:
			if (sp->f < 0)
				sp->f = -sp->f;
			break;
		case ABS_COMPLEX:
			sp->f = hypot(sp->c.real, sp->c.imag);
			break;

		case ACOS_FLOAT:
			sp->f = acos(sp->f);
			break;
		case ACOS_COMPLEX:
			sp->c = c_acos(sp->c);
			break;
		case ACOSH_FLOAT:
			sp->f = acosh(sp->f);
			break;
		case ACOSH_COMPLEX:
			sp->c = c_acosh(sp->c);
			break;
		case ASIN_FLOAT:
			sp->f = asin(sp->f);
			break;
		case ASIN_COMPLEX:
			sp->c = c_asin(sp->c);
			break;
		case ASINH_FLOAT:
			sp->f = asinh(sp->f);
			break;
		case ASINH_COMPLEX:
			sp->c = c_asinh(sp->c);
			break;
		case ATAN_FLOAT:
			sp->f = atan(sp->f);
			break;
		case ATAN_COMPLEX:
			sp->c = c_atan(sp->c);
			break;
		case ATANH_FLOAT:
			sp->f = atanh(sp->f);
			break;
		case ATANH_COMPLEX:
			sp->c = c_atanh(sp->c);
			break;
		case COS_FLOAT:
			sp->f = cos(sp->f);
			break;
		case COS_COMPLEX:
			sp->c = c_cos(sp->c);
			break;
		case COSH_FLOAT:
			sp->f = cosh(sp->f);
			break;
		case COSH_COMPLEX:
			sp->c = c_cosh(sp->c);
			break;
		case EXP_FLOAT:
			sp->f = exp(sp->f);
			break;
		case EXP_COMPLEX:
			sp->c = c_exp(sp->c);
			break;
		case LOG_FLOAT:
			sp->f = log(sp->f);
			break;
		case LOG_COMPLEX:
			sp->c = c_log(sp->c);
			break;
		case LOG10_FLOAT:
			sp->f = log10(sp->f);
			break;
		case LOG10_COMPLEX:
			sp->c = c_log10(sp->c);
			break;
		case SIN_FLOAT:
			sp->f = sin(sp->f);
			break;
		case SIN_COMPLEX:
			sp->c = c_sin(sp->c);
			break;
		case SINH_FLOAT:
			sp->f = sinh(sp->f);
			break;
		case SINH_COMPLEX:
			sp->c = c_sinh(sp->c);
			break;
		case SQRT_FLOAT:
			sp->f = sqrt(sp->f);
			break;
		case SQRT_COMPLEX:
			sp->c = c_sqrt(sp->c);
			break;
		case TAN_FLOAT:
			sp->f = tan(sp->f);
			break;
		case TAN_COMPLEX:
			sp->c = c_tan(sp->c);
			break;
		case TANH_FLOAT:
			sp->f = tanh(sp->f);
			break;
		case TANH_COMPLEX:
			sp->c = c_tanh(sp->c);
			break;

		default:
			sprintf(text, "unknown opcode %d", *cp);
			PyErr_SetString(ErrorObject, text);
			return NULL;
			break;
		}
		cp++;
       	}

	if (sp != stack) {
		PyErr_SetString(ErrorObject, "stack error");
		return NULL;
	}
	switch(self->type) {
	case INTEGER:
		result = (PyObject *)PyInt_FromLong(sp->i);
		break;
	case FLOAT:
		result = (PyObject *)PyFloat_FromDouble(sp->f);
		break;
	case COMPLEX:
		result = (PyObject *)PyComplex_FromCComplex(sp->c);
		break;
	default:
		Py_INCREF(None);
		result = None;
	}
	return result;
}

/* Arithmetic */

static char
numexpr_commontype(type1, type2)
	char type1;
	char type2;
{
	return max(type1, type2);
}

static PyNumExprObject *
numexpr_binary_op(a, b, type, op)
	PyNumExprObject *a;
	PyNumExprObject *b;
	char type;
	int op;
{
	PyNumExprObject *r = new_numexprobject();
	int error = 0;
	int i, j;
	int *cp;

	if (r != NULL) {
		r->type = type;
		r->nargs = max(a->nargs, b->nargs);
		r->nconstants = a->nconstants + b->nconstants;
		r->stacksize = max(a->stacksize, b->stacksize) + 1;
		r->codesize = a->codesize + b->codesize
			+ (a->type != type) + (b->type != type) + 1;
		if ((r->argtypes = PyMem_NEW(char, r->nargs+1)) != NULL) {
			for (i = 0; i < min(a->nargs, b->nargs); i++) {
				if (a->argtypes[i] == ' ')
					r->argtypes[i] = b->argtypes[i];
				else if (b->argtypes[i] == ' ')
					r->argtypes[i] = a->argtypes[i];
				else if (a->argtypes[i] == b->argtypes[i])
					r->argtypes[i] = a->argtypes[i];
				else {
					PyErr_SetString(ErrorObject,
						"inconsistent argument lists");
					error = 1;
				}
			}
			for (; i < r->nargs; i++)
				if (i < a->nargs)
					r->argtypes[i] = a->argtypes[i];
				else
					r->argtypes[i] = b->argtypes[i];
			r->argtypes[i] = '\0';
		}
		else
			error = 1;
		if ((r->args = PyMem_NEW(stack_entry, r->nargs)) == NULL)
			error = 1;
		if ((r->constants = PyMem_NEW(stack_entry, r->nconstants))
				!= NULL) {
			for (i = 0; i < a->nconstants; i++)
				r->constants[i] = a->constants[i];
			for (j = 0; j < b->nconstants; i++, j++)
				r->constants[i] = b->constants[j];
		}
		else
			error = 1;
		if ((r->code = PyMem_NEW(int, r->codesize)) != NULL) {
			cp = r->code;
			for (i = 0; i < a->codesize; i++)
				*cp++ = a->code[i];
			if (a->type != type)
				*cp++ = TYPE_CAST + a->type + NTYPES*type;
			for (i = 0; i < b->codesize;) {
				*cp++ = j = b->code[i++];
				if (j == GET_CONSTANT) {
					*cp++ = b->code[i++] + a->nconstants;
				}
				else if (j == GET_ARG) {
					*cp++ = b->code[i++];
				}
			}
			if (b->type != type)
				*cp++ = TYPE_CAST + b->type + NTYPES*type;
			*cp = op;
		}
		else
			error = 1;
		if ((r->stack = PyMem_NEW(stack_entry, r->stacksize)) == NULL)
			error = 1;
		if (error) {
			numexpr_dealloc(r);
			r = NULL;
		}
	}
	return r;
}

static PyNumExprObject *
numexpr_unary_op(a, op)
	PyNumExprObject *a;
	int op;
{
	PyNumExprObject *r = new_numexprobject();
	int error = 0;
	int i;
	int *cp;

	if (r != NULL) {
		r->type = a->type;
		r->nargs = a->nargs;
		r->nconstants = a->nconstants;
		r->stacksize = a->stacksize;
		r->codesize = a->codesize + 1;
		if ((r->argtypes = PyMem_NEW(char, r->nargs+1)) != NULL)
			strcpy(r->argtypes, a->argtypes);
		else
			error = 1;
		if ((r->args = PyMem_NEW(stack_entry, r->nargs)) == NULL)
			error = 1;
		if ((r->constants = PyMem_NEW(stack_entry, r->nconstants))
				!= NULL)
			for (i = 0; i < a->nconstants; i++)
				r->constants[i] = a->constants[i];
		else
			error = 1;
		if ((r->code = PyMem_NEW(int, r->codesize)) != NULL) {
			cp = r->code;
			for (i = 0; i < a->codesize; i++)
				*cp++ = a->code[i];
			*cp = op;
		}
		if ((r->stack = PyMem_NEW(stack_entry, r->stacksize)) == NULL)
			error = 1;
		if (error) {
			numexpr_dealloc(r);
			r = NULL;
		}
	}
	return r;
}

static PyObject *
numexpr_add(a, b)
	PyNumExprObject *a;
	PyNumExprObject *b;
{
	char type = numexpr_commontype(a->type, b->type);
	return (PyObject *)numexpr_binary_op(a, b, type, ADD+type);
}

static PyObject *
numexpr_sub(a, b)
	PyNumExprObject *a;
	PyNumExprObject *b;
{
	char type = numexpr_commontype(a->type, b->type);
	return (PyObject *)numexpr_binary_op(a, b, type, SUB+type);
}

static PyObject *
numexpr_mul(a, b)
	PyNumExprObject *a;
	PyNumExprObject *b;
{
	char type = numexpr_commontype(a->type, b->type);
	return (PyObject *)numexpr_binary_op(a, b, type, MUL+type);
}

static PyObject *
numexpr_div(a, b)
	PyNumExprObject *a;
	PyNumExprObject *b;
{
	char type = numexpr_commontype(a->type, b->type);
	return (PyObject *)numexpr_binary_op(a, b, type, DIV+type);
}

static PyObject *
numexpr_pow(a, b)
	PyNumExprObject *a;
	PyNumExprObject *b;
{
	char type = numexpr_commontype(a->type, b->type);
	return (PyObject *)numexpr_binary_op(a, b, type, POW+type);
}

static PyObject *
numexpr_neg(a)
	PyNumExprObject *a;
{
	return (PyObject *)numexpr_unary_op(a, NEG+a->type);
}

static PyObject *
numexpr_pos(a)
	PyNumExprObject *a;
{
	Py_INCREF(a);
	return (PyObject *)a;
}

static PyObject *
numexpr_abs(a)
	PyNumExprObject *a;
{
	PyNumExprObject *r = numexpr_unary_op(a, ABS+a->type);
	if (r != NULL && r->type == COMPLEX)
		r->type = FLOAT;
	return (PyObject *)r;
}

static int
numexpr_nonzero(a)
	PyNumExprObject *a;
{
	return 1;
}


/* Type conversion */

static void
numexpr_convert(value, type_in, type_out)
	stack_entry *value;
	int type_in;
	int type_out;
{
	switch (type_in) {
		case INTEGER:
			if (type_out == FLOAT)
				value->f = value->i;
			else
				value->c.real = value->i;
				value->c.imag = 0;
			break;
		case FLOAT:
			if (type_out == INTEGER)
				value->i = value->f;
			else
				value->c.real = value->f;
				value->c.imag = 0;
			break;
		case COMPLEX:
			if (type_out == INTEGER)
				value->i = value->c.real;
			else
				value->f = value->c.real;
			break;
	}
}

/* Type coercion: Numbers are converted to constant expressions */

static PyObject *
numexpr_const(value, type_in, type_out)
	stack_entry value;
	int type_in, type_out;
{
	PyNumExprObject *rv;
	int error = 0;

	rv = new_numexprobject();
	if (rv != NULL) {
		rv->nargs = 0;
		rv->nconstants = 1;
		rv->codesize = 2;
		rv->stacksize = 1;
		rv->type = type_out;
		if (type_in != type_out)
			numexpr_convert(&value, type_in, type_out);
		if ((rv->constants = PyMem_NEW(stack_entry, rv->nconstants))
				!= NULL)
			*rv->constants = value;
		else
			error = 1;
		if ((rv->code = PyMem_NEW(int, rv->codesize)) != NULL) {
			rv->code[0] = GET_CONSTANT;
			rv->code[1] = 0;
		}
		else
			error = 1;
		if ((rv->stack = PyMem_NEW(stack_entry, rv->stacksize)) == NULL)
			error = 1;
		if (error) {
			numexpr_dealloc(rv);
			rv = NULL;
		}
	}
	return (PyObject *)rv;
}

static void
numexpr_coercenumber(value, type, number, numexpr)
	stack_entry value;
	int type;
	PyNumExprObject **number;
	PyNumExprObject **numexpr;
{
	int result_type = numexpr_commontype(type, (*numexpr)->type);

	*number = (PyNumExprObject *)numexpr_const(value, type, result_type);
	if ((*numexpr)->type != result_type)
		*numexpr = numexpr_unary_op(*numexpr,
			TYPE_CAST + (*numexpr)->type + NTYPES*result_type);
	else
		Py_INCREF(*numexpr);
}

static int
numexpr_coerce(a, b)
	PyObject **a;
	PyObject **b;
{
	PyObject **number;
	PyNumExprObject **numexpr;
	stack_entry value;

	if (PyNumExpr_Check(*a)) {
		numexpr = (PyNumExprObject **)a;
		number = b;
	}
	else {
		numexpr = (PyNumExprObject **)b;
		number = a;
	}
	if (PyInt_Check(*number)) {
		value.i = PyInt_AsLong(*number);
		numexpr_coercenumber(value, INTEGER, number, numexpr);
		return 0;
	}
	else if (PyFloat_Check(*number)) {
		value.f = PyFloat_AsDouble(*number);
		numexpr_coercenumber(value, FLOAT, number, numexpr);
		return 0;
	}
	else if (PyComplex_Check(*number)) {
		value.c = PyComplex_AsCComplex(*number);
		numexpr_coercenumber(value, COMPLEX, number, numexpr);
		return 0;
	}
	else
		return 1;
}

/* Module documentation string */

static char PyNumExpr_Type__doc__[] = 
"Compiled numerical expressions";

/* Type definition */

static PyNumberMethods numexpr_as_number = {
	(binaryfunc)numexpr_add, /*nb_add*/
	(binaryfunc)numexpr_sub, /*nb_subtract*/
	(binaryfunc)numexpr_mul, /*nb_multiply*/
	(binaryfunc)numexpr_div, /*nb_divide*/
	0,		/*nb_remainder*/
	0,		/*nb_divmod*/
	(ternaryfunc)numexpr_pow, /*nb_power*/
	(unaryfunc)numexpr_neg, /*nb_negative*/
	(unaryfunc)numexpr_pos, /*nb_positive*/
	(unaryfunc)numexpr_abs, /*nb_absolute*/
	(inquiry)numexpr_nonzero, /*nb_nonzero*/
	0,		/*nb_invert*/
	0,		/*nb_lshift*/
	0,		/*nb_rshift*/
	0,		/*nb_and*/
	0,		/*nb_xor*/
	0,		/*nb_or*/
	(coercion)numexpr_coerce, /*nb_coerce*/
	0,		/*nb_int*/
	0,		/*nb_long*/
	0,		/*nb_float*/
	0,		/*nb_oct*/
	0,		/*nb_hex*/
};

static PyTypeObject PyNumExpr_Type = {
	PyObject_HEAD_INIT(&PyType_Type)
	0,			/*ob_size*/
	"numexpr",			/*tp_name*/
	sizeof(PyNumExprObject),	/*tp_basicsize*/
	0,			/*tp_itemsize*/
	/* methods */
	(destructor)numexpr_dealloc, /*tp_dealloc*/
	0,			/*tp_print*/
	(getattrfunc)numexpr_getattr, /*tp_getattr*/
	0, 			/*tp_setattr*/
	0,			/*tp_compare*/
	(reprfunc)numexpr_repr, /*tp_repr*/
	&numexpr_as_number,	/*tp_as_number*/
	0,			/*tp_as_sequence*/
	0,			/*tp_as_mapping*/
	0,			/*tp_hash*/
	(ternaryfunc)numexpr_call,	/*tp_call*/
	(reprfunc)numexpr_repr,		/*tp_str*/

	/* Space for future expansion */
	0L,0L,0L,0L,
	PyNumExpr_Type__doc__	/* Documentation string */
};
/* --------------------------------------------------------------------- */

/* Return a new variable object. The (integer) argument
   indicates the position of the variable in the argument
   list of the compiled expression; it defaults to zero. */

static PyNumExprObject *
new_variable(args)
	PyObject *args;
{
	PyNumExprObject *rv;
	int argnum = 0;
	int error = 0;
	int i;

	PyArg_ParseTuple(args, "|i:numexpr variable", &argnum);
	rv = new_numexprobject();
	if (rv != NULL) {
		rv->nargs = argnum + 1;
		rv->stacksize = 1;
		rv->codesize = 2;
		if ((rv->argtypes = PyMem_NEW(char, rv->nargs+1)) != NULL) {
			for (i = 0; i < rv->nargs; i++)
				rv->argtypes[i] = ' ';
			rv->argtypes[i] = '\0';
		}
		else
			error = 1;
		if ((rv->args = PyMem_NEW(stack_entry, rv->nargs)) == NULL)
			error = 1;
		if ((rv->code = PyMem_NEW(int, rv->codesize)) != NULL) {
			rv->code[0] = GET_ARG;
			rv->code[1] = argnum;
		}
		else
			error = 1;
		if ((rv->stack = PyMem_NEW(stack_entry, rv->stacksize)) == NULL)
			error = 1;
		if (error) {
			numexpr_dealloc(rv);
			rv = NULL;
		}
	}
	return rv;
}

static PyObject *
numexpr_intvar(self, args)
	PyObject *self; /* Not used */
	PyObject *args;
{
	PyNumExprObject *rv = new_variable(args);
	if (rv != NULL) {
		rv->argtypes[rv->nargs-1] = 'l';
		rv->type = INTEGER;
	}
	return (PyObject *)rv;
}

static PyObject *
numexpr_floatvar(self, args)
	PyObject *self; /* Not used */
	PyObject *args;
{
	PyNumExprObject *rv = new_variable(args);
	if (rv != NULL) {
		rv->argtypes[rv->nargs-1] = 'd';
		rv->type = FLOAT;
	}
	return (PyObject *)rv;
}

static PyObject *
numexpr_complexvar(self, args)
	PyObject *self; /* Not used */
	PyObject *args;
{
	PyNumExprObject *rv = new_variable(args);
	if (rv != NULL) {
		rv->argtypes[rv->nargs-1] = 'D';
		rv->type = COMPLEX;
	}
	return (PyObject *)rv;
}

/* List of functions defined in the module */

static struct PyMethodDef numexpr_functions[] = {
	{"FloatVariable",	numexpr_floatvar, 1},
	{"IntegerVariable",	numexpr_intvar,	1},
	{"ComplexVariable",	numexpr_complexvar, 1},
	{NULL,	NULL}		/* sentinel */
};

/* Various math functions */

#if 0
static PyObject *
numexpr_sqrt(self)
	PyNumExprObject *self;
{
	PyNumExprObject *temp = self;
	PyNumExprObject *r;

	if (self->type == INTEGER) {
		temp = numexpr_unary_op(self, INTEGER_FLOAT);
		temp->type = FLOAT;
	}
	if (temp->type == COMPLEX)
		r = numexpr_unary_op(temp, SQRT_COMPLEX);
	else
		r = numexpr_unary_op(temp, SQRT_FLOAT);
	if (temp != self)
		numexpr_dealloc(temp);
	return (PyObject *)r;
}
#endif

static PyObject *
numexpr_mathfunc(arg, float_op, complex_op)
	PyNumExprObject *arg;
	int float_op;
	int complex_op;
{
	PyNumExprObject *temp = arg;
	PyNumExprObject *r;

	if (arg->type == INTEGER) {
		temp = numexpr_unary_op(arg, INTEGER_FLOAT);
		temp->type = FLOAT;
	}
	if (temp->type == COMPLEX)
		r = numexpr_unary_op(temp, complex_op);
	else
		r = numexpr_unary_op(temp, float_op);
	if (temp != arg)
		numexpr_dealloc(temp);
	return (PyObject *)r;
}

#define add_mathfunc(func_name, float_op, complex_op) \
	static PyObject * \
	func_name(self) \
		PyNumExprObject *self; \
	{ \
		return numexpr_mathfunc(self, float_op, complex_op); \
	}

add_mathfunc(numexpr_acos, ACOS_FLOAT, ACOS_COMPLEX)
add_mathfunc(numexpr_acosh, ACOSH_FLOAT, ACOSH_COMPLEX)
add_mathfunc(numexpr_asin, ASIN_FLOAT, ASIN_COMPLEX)
add_mathfunc(numexpr_asinh, ASINH_FLOAT, ASINH_COMPLEX)
add_mathfunc(numexpr_atan, ATAN_FLOAT, ATAN_COMPLEX)
add_mathfunc(numexpr_atanh, ATANH_FLOAT, ATANH_COMPLEX)
add_mathfunc(numexpr_cos, COS_FLOAT, COS_COMPLEX)
add_mathfunc(numexpr_cosh, COSH_FLOAT, COSH_COMPLEX)
add_mathfunc(numexpr_exp, EXP_FLOAT, EXP_COMPLEX)
add_mathfunc(numexpr_log, LOG_FLOAT, LOG_COMPLEX)
add_mathfunc(numexpr_log10, LOG10_FLOAT, LOG10_COMPLEX)
add_mathfunc(numexpr_sin, SIN_FLOAT, SIN_COMPLEX)
add_mathfunc(numexpr_sinh, SINH_FLOAT, SINH_COMPLEX)
add_mathfunc(numexpr_sqrt, SQRT_FLOAT, SQRT_COMPLEX)
add_mathfunc(numexpr_tan, TAN_FLOAT, TAN_COMPLEX)
add_mathfunc(numexpr_tanh, TANH_FLOAT, TANH_COMPLEX)


/* List of methods of type "numexpr" */

static struct PyMethodDef numexpr_methods[] = {
	{"acos",	(PyCFunction)numexpr_acos, 1},
	{"acosh",	(PyCFunction)numexpr_acosh, 1},
	{"asin",	(PyCFunction)numexpr_asin, 1},
	{"asinh",	(PyCFunction)numexpr_asinh, 1},
	{"atan",	(PyCFunction)numexpr_atan, 1},
	{"atanh",	(PyCFunction)numexpr_atanh, 1},
	{"cos",		(PyCFunction)numexpr_cos, 1},
	{"cosh",	(PyCFunction)numexpr_cosh, 1},
	{"exp",		(PyCFunction)numexpr_exp, 1},
	{"log",		(PyCFunction)numexpr_log, 1},
	{"log10",	(PyCFunction)numexpr_log10, 1},
	{"sin",		(PyCFunction)numexpr_sin, 1},
	{"sinh",	(PyCFunction)numexpr_sinh, 1},
	{"sqrt",	(PyCFunction)numexpr_sqrt, 1},
	{"tan",		(PyCFunction)numexpr_tan, 1},
	{"tanh",	(PyCFunction)numexpr_tanh, 1},
	{NULL,		NULL}		/* sentinel */
};


/* Initialization function for the module (*must* be called initnumexpr) */

void
initnumexpr()
{
	PyObject *m, *d;

	/* Create the module and add the functions */
	m = Py_InitModule("numexpr", numexpr_functions);

	/* Add some symbolic constants to the module */
	d = PyModule_GetDict(m);
	ErrorObject = PyString_FromString("NumExprError");
	PyDict_SetItemString(d, "error", ErrorObject);

	/* Check for errors */
	if (PyErr_Occurred())
		Py_FatalError("can't initialize module numexpr");
}

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

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

From jjh@Goldilocks.LCS.MIT.EDU  Tue Jan 23 18:00:16 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Tue, 23 Jan 96 13:00:16 EST
Subject: [PYTHON MATRIX-SIG] floating point equalities
Message-ID: <9601231800.AA29105@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


In preparation for the 0.30 release (still on for Friday) I've been
cleaning up the array math functions.

I'm now working on improving the floating point equality operator.  My
understanding is that doing a == b is unreasonable for floating point
numbers, and instead the test should be something like 

abs(a-b) < TOLERANCE*abs(a)

Rather than have me try and rederive what this should look like from
my vague memories of the IEEE floating point standard, I was wondering
if anybody out there has a good chunk of code for doing this
comparision?

Thanks, 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  Tue Jan 23 18:26:24 1996
From: guido@CNRI.Reston.VA.US (Guido van Rossum)
Date: Tue, 23 Jan 1996 13:26:24 -0500
Subject: [PYTHON MATRIX-SIG] floating point equalities
In-Reply-To: Your message of "Tue, 23 Jan 1996 13:00:16 EST."
 <9601231800.AA29105@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
References: <9601231800.AA29105@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <199601231826.NAA15424@monty>

> I'm now working on improving the floating point equality operator.  My
> understanding is that doing a == b is unreasonable for floating point
> numbers, and instead the test should be something like 
> 
> abs(a-b) < TOLERANCE*abs(a)

Hm.  If you put this in the array module it would be a reasonable
expectation that it would also work for ordinary Python floats, which
it doesn't.  Also, the tolerance may be application dependent or
dependent on the part of the application that's doing this, so it may
need to be specified in the operation.

I'd advise to continue using C's '==' operator for floats (which is
what ordinary Python floats do).  Users who know enough to write
numerical code should also know not to compare for equality.

(What you could do is provide a method or function for comparisons
where you can pass the tolerance in as an argument.)

--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@Goldilocks.LCS.MIT.EDU  Tue Jan 23 18:48:21 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Tue, 23 Jan 96 13:48:21 EST
Subject: [PYTHON MATRIX-SIG] floating point equalities
In-Reply-To: <199601231826.NAA15424@monty> (message from Guido van Rossum on Tue, 23 Jan 1996 13:26:24 -0500)
Message-ID: <9601231848.AA29834@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


   From: Guido van Rossum <guido@CNRI.Reston.VA.US>

   > I'm now working on improving the floating point equality operator.  My
   > understanding is that doing a == b is unreasonable for floating point
   > numbers, and instead the test should be something like 
   > 
   > abs(a-b) < TOLERANCE*abs(a)

   Hm.  If you put this in the array module it would be a reasonable
   expectation that it would also work for ordinary Python floats, which
   it doesn't.  Also, the tolerance may be application dependent or
   dependent on the part of the application that's doing this, so it may
   need to be specified in the operation.

   I'd advise to continue using C's '==' operator for floats (which is
   what ordinary Python floats do).  Users who know enough to write
   numerical code should also know not to compare for equality.

   (What you could do is provide a method or function for comparisons
   where you can pass the tolerance in as an argument.)

I'm still curious to see what the more numerically inclined folks have
to say on this, but you're obviously right that this should be
provided as an additional function, not the default comparision
behavior.

I'd like to have a method approxEqual (or some similar name) so that
a.approxEqual(b) will "do the right thing".  I had believed that there
was some sort of consensus in the numerical programming community on
what the right thing is for floating point numbers, if I'm wrong on
this, I'd like to know that too.

Note: part of why this came up is the fact that on my development
system (1j)**2 == (-1+1.22460635382e-16j).  I'd really like to be able
to have some way to say approxEqual((1j)**2, -1) and have it come out
true (OK, I have an ad hoc solution that works, what I want is the
"right" solution if there is one out there).

-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 Jan 23 19:05:49 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 23 Jan 1996 14:05:49 -0500
Subject: [PYTHON MATRIX-SIG] floating point equalities
In-Reply-To: <9601231800.AA29105@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601231905.OAA01142@cyclone.ERE.UMontreal.CA>


   I'm now working on improving the floating point equality operator.  My
   understanding is that doing a == b is unreasonable for floating point
   numbers, and instead the test should be something like 

   abs(a-b) < TOLERANCE*abs(a)

I don't agree. First, there are cases where testing for equality
makes sense (e.g. if you know that the number represents an integer,
or if you want to detect an underflow by comparing to zero).
Second, standard Python floats use normal equality, so arrays
should behave identically.

On the other hand, having a test with tolerance would be very
useful and make code more readable. APL has such a feature
(using a global variable for the tolerance, which for Python
is not such a great idea), which I like a lot. And since
the comparison "operators" for arrays are methods anyway,
it is easy to have both, with an optional second argument
for the tolerance. I.e. you would write
   a.equal(b)
for a normal equality test and
   a.equal(b, 1e-6)
for a test with a given tolerance. As for the form of a test with
tolerance, I am not sure whether there is a generally accepted best
one. I have seen (and used) the form you have given above, but
also the more symmetric form
   abs(a-b) < TOLERANCE*(abs(a)+abs(b))
(although I wonder whether this is ever necessary). Hopefully
the mathematicians among us can say something more definite.


And now for something completely different...

While rereading the discussion about the beta release, I noticed that
there was no mention at all of how to deal with functions of finite
rank. Although there are none in the current package, they will
appear in the application-specific packages to be written later
(e.g. linear algebra), so there should be a general mechanism for
dealing with them.

-------------------------------------------------------------------------------
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 strow@umbc.edu  Tue Jan 23 19:40:48 1996
From: strow@umbc.edu (L. Larrabee Strow)
Date: Tue, 23 Jan 1996 14:40:48 -0500
Subject: [PYTHON MATRIX-SIG] floating point equalities
Message-ID: <v02130506ad2ae9c06db8@[130.85.140.14]>

>In preparation for the 0.30 release (still on for Friday) I've been
>cleaning up the array math functions.
>
>I'm now working on improving the floating point equality operator.  My
>understanding is that doing a == b is unreasonable for floating point
>numbers, and instead the test should be something like
>
>abs(a-b) < TOLERANCE*abs(a)
>
>Rather than have me try and rederive what this should look like from
>my vague memories of the IEEE floating point standard, I was wondering
>if anybody out there has a good chunk of code for doing this
>comparision?
>
>Thanks, Jim
>

Let the user decide how to compare for equality.  We are used to avoiding
the a==b problem.  It would probably be a mistake to "help" us too much,
since we might get lazy and make even more subtle mistakes.

--
L. Larrabee Strow                            E-mail: strow@umbc.edu
Department of Physics                        FAX   : (410) 455-1072
University of Maryland Baltimore County      Phone : (410) 455-2528
5401 Wilkens Avenue
Baltimore, MD 21228-5398                  



=================
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  Tue Jan 23 19:37:35 1996
From: guido@CNRI.Reston.VA.US (Guido van Rossum)
Date: Tue, 23 Jan 1996 14:37:35 -0500
Subject: [PYTHON MATRIX-SIG] floating point equalities
In-Reply-To: Your message of "Tue, 23 Jan 1996 13:48:21 EST."
 <9601231848.AA29834@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
References: <9601231848.AA29834@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <199601231937.OAA15633@monty>

> I'd like to have a method approxEqual (or some similar name) so that
> a.approxEqual(b) will "do the right thing".  I had believed that there
> was some sort of consensus in the numerical programming community on
> what the right thing is for floating point numbers, if I'm wrong on
> this, I'd like to know that too.

Cool.

> Note: part of why this came up is the fact that on my development
> system (1j)**2 == (-1+1.22460635382e-16j).  I'd really like to be able
> to have some way to say approxEqual((1j)**2, -1) and have it come out
> true (OK, I have an ad hoc solution that works, what I want is the
> "right" solution if there is one out there).

I bet this is because in x**y, Python currently coerces y, meaning you
were really calculating 1.0j ** 2.0j...

(Note that the (by now pathetically incomplete) Python test suite has
a similar problem and solution when testing the pow() function.)

--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  Tue Jan 23 20:29:31 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 23 Jan 1996 15:29:31 -0500
Subject: [PYTHON MATRIX-SIG] floating point equalities
In-Reply-To: <9601231848.AA29834@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601232029.PAA07104@cyclone.ERE.UMontreal.CA>


   Note: part of why this came up is the fact that on my development
   system (1j)**2 == (-1+1.22460635382e-16j).  I'd really like to be able
   to have some way to say approxEqual((1j)**2, -1) and have it come out

Are you sure that you have installed the latest version of my complex
object? It should give 1j**2 == -1., exactly.  The reason is that
complex_power() detects that the exponent is actually an integer (no
fractional or imaginary part), and then calls c_powi(), which in turn
calls c_powu() because the exponent is positive and less than
100. c_powu() reduces the power calculation to an optimized sequence
of multiplications. Therefore 1j**2 is exactly equivalent to
1j*1j. (And yes, I have traced this example with a debugger right now
because I was a bit worried).

What does 1j*1j give on your system? It ought to be exactly -1., since
there are no round-off errors in this calculation.

I realize that this has nothing to do with doing comparisons in
general, of course...

-------------------------------------------------------------------------------
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@Goldilocks.LCS.MIT.EDU  Tue Jan 23 20:39:21 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Tue, 23 Jan 96 15:39:21 EST
Subject: [PYTHON MATRIX-SIG] floating point equalities
In-Reply-To: <199601232029.PAA07104@cyclone.ERE.UMontreal.CA> (hinsenk@ere.umontreal.ca)
Message-ID: <9601232039.AA01063@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


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


      Note: part of why this came up is the fact that on my development
      system (1j)**2 == (-1+1.22460635382e-16j).  I'd really like to be able
      to have some way to say approxEqual((1j)**2, -1) and have it come out

   Are you sure that you have installed the latest version of my complex
   object? It should give 1j**2 == -1., exactly.  The reason is that
   complex_power() detects that the exponent is actually an integer (no
   fractional or imaginary part), and then calls c_powi(), which in turn
   calls c_powu() because the exponent is positive and less than
   100. c_powu() reduces the power calculation to an optimized sequence
   of multiplications. Therefore 1j**2 is exactly equivalent to
   1j*1j. (And yes, I have traced this example with a debugger right now
   because I was a bit worried).

   What does 1j*1j give on your system? It ought to be exactly -1., since
   there are no round-off errors in this calculation.

   I realize that this has nothing to do with doing comparisons in
   general, of course...

My fault, I'm still running with an old version of your patch.
I'll install the new one before I do much more testing.  (Still, this
problem comes up in many other places).

-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 Jan 23 20:39:57 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 23 Jan 1996 15:39:57 -0500
Subject: [PYTHON MATRIX-SIG] floating point equalities
In-Reply-To: <199601231937.OAA15633@monty> (message from Guido van Rossum on Tue, 23 Jan 1996 14:37:35 -0500)
Message-ID: <199601232039.PAA07827@cyclone.ERE.UMontreal.CA>


   I bet this is because in x**y, Python currently coerces y, meaning you
   were really calculating 1.0j ** 2.0j...

   (Note that the (by now pathetically incomplete) Python test suite has
   a similar problem and solution when testing the pow() function.)

For complex numbers, 1j**2.0 is calculated as 1j**2. And with my
set of patches, the same happens for real numbers. You still don't
get the full efficiency of an integer exponentiation, but at least
the accuracy.

That is of course no argument for not fixing the pow() coercion
problem...

-------------------------------------------------------------------------------
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 dubois1@llnl.gov  Tue Jan 23 21:59:47 1996
From: dubois1@llnl.gov (Paul. Dubois)
Date: Tue, 23 Jan 1996 13:59:47 -0800
Subject: [PYTHON MATRIX-SIG] floating point equalities
References: <9601231848.AA29834@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <31055A53.739E@llnl.gov>

Guido is clearly right.
As for how to do approxEqual(a,b), there is no one right answer.
There are two ways of measuring error, relative and absolute.
Relative is usually defined as abs(a-b)/max(abs(a),abs(b)). 
Absolute is just abs(a-b).

Suppose the two numbers are 10**-15 and 10**-16. Depending on what you
are doing, the difference between these two is either (a) a factor of
10, which sounds "large", or (b) about 10**-15, which sounds small.

Many people use a "mixed" critera, considering two numbers equal if
their relative difference is small or their absolute difference is
(perhaps a different size of) small. You see tests like:

abs(a-b) < rel_tol * abs(a) + abs_tol

But small is still hard to be precise about, since it really depends on
context. If you get a relative error of 1.e-8 solving a linear system it
might be expected, but that same number might be a sign of trouble in
other contexts where errors more like 1.e-14 are normal.

One solution is say a class RealNumberComparer, which contains
attributes maximum_relative_error, maximum_absolute_error, routines to
set these (with some reasonable defaults set on creation) and an
equals(a,b) to carry out the test.
-- 
Paul F. Dubois, L-472				(510)-422-5426
Lawrence Livermore National Laboratory		FAX (510)-423-9969
Livermore, CA 94550				dubois1@llnl.gov
Consulting: PaulDubois@aol.com

=================
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 Jan 24 16:18:19 1996
From: jfulton@usgs.gov (Jim Fulton, U.S. Geological Survey)
Date: Wed, 24 Jan 1996 11:18:19 -0500
Subject: [PYTHON MATRIX-SIG] Summary for main list?
Message-ID: <9601241118.ZM24858@dsdbqvarsa.er.usgs.gov>

A summary of our activities to the Python list is probably long overdue.  Jim
or others, do you already have anything that would be good to post.  Do we have
a complete summary of the work?  Somethink like the original proposal that has
been updated to reflect decisions made?

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@Goldilocks.LCS.MIT.EDU  Thu Jan 25 12:34:25 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Thu, 25 Jan 96 07:34:25 EST
Subject: [PYTHON MATRIX-SIG] Summary for main list?
In-Reply-To: <9601241118.ZM24858@dsdbqvarsa.er.usgs.gov> (jfulton@usgs.gov)
Message-ID: <9601251234.AA06874@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


There is no complete summary of the work anywhere.  At this point, the
best summary is going to probably be the documentation for the
NumericPython extension package (completed in time for the first beta
release).  

I'm still on the schedule I recently included in my proposals for a
final set of naming conventions, etc.  This includes a general beta
release (advertised in the main newsgroup) on 2/12.

Personally, I'd just as soon wait until then to bring the main python
group "up to date".

If somebody wants to post a generic message reminding people of the
existence of the matrix-sig and its purpose, that might be useful.

-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@Goldilocks.LCS.MIT.EDU  Thu Jan 25 13:13:02 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Thu, 25 Jan 96 08:13:02 EST
Subject: [PYTHON MATRIX-SIG] type coercion one more time
Message-ID: <9601251313.AA07030@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


I've been working to design a stable version of automatic type
coercion that everybody (including myself) can be happy with.  The
following is what I have.  Much of this is in line with the C rules
for type coercion (at least according to my old K&R).  I will use the
standard C type names (double means a python float).

Only the following three automatic coercions are allowed:

1) Any integer type can be coerced to a float, a double, a complex float or
a complex double.

2) A float can only be coerced to a complex float.

3) A double can only be coerced to a complex double.

Explanation:

The following type hierarchy is assumed:

INTEGER < FLOAT < COMPLEX

Within each level there are a number of possible precisions.  No
automatic coercion will take place between these precisions.

This remains completely consistent with the existing python automatic
type coercion.

Examples:

a_t = array([x,y,z,...], 't') # Where t is a legal typecode

1 - signed byte
l - long
f - float
d - double
F - complex float
D - complex double

a_l * a_d = a_d
a_f * a_l = a_f
a_f * a_d = TypeError Exception raised
a_d * a_D = a_D
a_1 * a_l = TypeError Exception raised

Comments? - 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 Jan 25 14:52:01 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Thu, 25 Jan 1996 09:52:01 -0500
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: <9601251313.AA07030@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601251452.JAA02955@cyclone.ERE.UMontreal.CA>


   Only the following three automatic coercions are allowed:

   1) Any integer type can be coerced to a float, a double, a complex float or
   a complex double.

   2) A float can only be coerced to a complex float.

   3) A double can only be coerced to a complex double.

Sounds OK for me.

   This remains completely consistent with the existing python automatic
   type coercion.

Which is all I really care about...

-------------------------------------------------------------------------------
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  Thu Jan 25 14:57:56 1996
From: guido@CNRI.Reston.VA.US (Guido van Rossum)
Date: Thu, 25 Jan 1996 09:57:56 -0500
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: Your message of "Thu, 25 Jan 1996 08:13:02 EST."
 <9601251313.AA07030@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
References: <9601251313.AA07030@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <199601251457.JAA21034@monty>

> No automatic coercion will take place between these precisions.

This surprises me (especially since C does support float -> double
coercions).  Would you care to explain it?

--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@Goldilocks.LCS.MIT.EDU  Thu Jan 25 15:45:58 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Thu, 25 Jan 96 10:45:58 EST
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: <199601251457.JAA21034@monty> (message from Guido van Rossum on Thu, 25 Jan 1996 09:57:56 -0500)
Message-ID: <9601251545.AA08514@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


   From: Guido van Rossum <guido@CNRI.Reston.VA.US>

   > No automatic coercion will take place between these precisions.

   This surprises me (especially since C does support float -> double
   coercions).  Would you care to explain it?

Naive users of the system are only expected to use arrays of longs,
doubles, and complex doubles.  I wanted to make sure that all of the
automatic coercion rules would work for these most frequently used
types so that they'll work just like the corresponding python scalars.

On the other hand, I see the other types as being used for cases where
the programmer really wants to use a particular precision, ie. 2-byte
integers for dealing with 16-bit sound data.  In a case like this it
seems decidely unfriendly to automatically coerce to another
precision.

One can imagine dividing each sample in a sound by 2, and then trying
to play it back and hearing garbage because it got automatically
converted to an array of longs during the division.


I do have one other possible set of rules that I would be happy with.
These are basically the same as the last post, except:

4) Coercion to a higher precision is allowed within the main
groupings.

5) The precision of a python scalar is allowed to change to match the
other arguments (3.14 can be either a float or a double depending on
which one is "desired").

I don't like this rule, but without it I think that it is too easy to
get bitten by python scalars when writing "real" code.

Does this make sense?

Do people prefer this revised scheme?

-Jim



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

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

From stoll@atr-sw.atr.co.jp  Thu Jan 25 16:09:53 1996
From: stoll@atr-sw.atr.co.jp (Perry A. Stoll)
Date: Fri, 26 Jan 1996 01:09:53 +0900
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: Your message of "Thu, 25 Jan 1996 08:13:02 JST"
References: <9601251313.AA07030@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <199601251609.BAA02646@ciris21.atr-sw.atr.co.jp>


>>>>> "JH" == James Hugunin <jjh@Goldilocks.LCS.MIT.EDU> writes:
    JH> I've been working to design a stable version of automatic type
    JH> coercion that everybody (including myself) can be happy with.

Sounds good. I offer my support for continuing something similar to
the current scheme.

    JH> Only the following three automatic coercions are allowed:

    JH> 1) Any integer type can be coerced to a float, a double, a
    JH> complex float or a complex double.

Does 'any integer' type mean byte,short,integer? If so, OK.

    JH> 2) A float can only be coerced to a complex float.
    JH> 3) A double can only be coerced to a complex double.
    JH> Explanation:
    JH> The following type hierarchy is assumed:
    JH> INTEGER < FLOAT < COMPLEX
    JH> Within each level there are a number of possible precisions.

True, and it would be unrealistic to do arbitrary coercions. 

    JH> No automatic coercion will take place between these
    JH> precisions.

But there is no reason not to do coercion to a greater precision. See
below.

    JH> This remains completely consistent with the existing python
    JH> automatic type coercion.

To some extent. But there is no access in Python to most underlying C
numeric types, for good or bad. Good in most cases, bad in C/Fortran
interfacing cases. It seems like we're trying to add these types to
Python - this could be difficult.

    JH> a_l * a_d = a_d
    JH> a_f * a_l = a_f
    JH> a_f * a_d = TypeError Exception raised
    JH> a_d * a_D = a_D
    JH> a_1 * a_l = TypeError Exception raised

Raising exceptions in these circumstances seems a bit arbitrary. 

I think the source of your problem is the difference between Python's
floats (i.e. C doubles) and C floats. I don't know any way to specify
a C float in Python - does anyone? It seems the idealistic approach of
having only one floating point representation in Python is at odds
with peoples' desire to access C floats.

Also, I don't see how the scheme you outline above will solve your problem
   Array_f([1.0,2.0,3.0]) * 2.0 = Array_f([2.0,4.0,6.0]) 
since '2.0' is interpreted as a Python 'float', i.e. a C double. From
the scheme you propose above, this would raise an exception.  Assuming
it is too late to add '2.0f' to Python (or a better type specification
scheme as outlined earlier on this list), I can't think of a way to
get around this without explicitly doing an ungainly Matrix_f(2.0). Of 
course, if it matters this much, you could always do M_f = Matrix_f
and have M_f(2.0) scattered through your code. 

  The more I think about this (and since I'm thinking as I'm writing,
this is at the expense of conciseness - sorry!), the more I think your
situation is outside the Python norm and should really be viewed as
such.

  Although it may not solve your problem of C floats, I think it makes
more sense to allow conversion to any "higher" type, where "higher"
means higher in the list of types, i.e.
       b < s < i < l < f < d
Also:  (b,s,i,l,f) <= C
       (b,s,i,l,f,d,C) <= D

With the exception of the last bit, isn't this how the present (0.2)
release works?

  Also, I don't recall anyone presenting a list of 'nice' names for
the Matrix functions as Konrad has been advocating. I think having
these is a good idea; the type code that we have now has always seemed
somehow counter to (my view of) the Python 'do-it-the-Right-Way'
attitude.  If I actually list them all out here, maybe this will force
the issue and start some discussion. Comments on the following?

   Array_Char, Array_UChar
   Array_Short, Array_UShort
   Array_Integer,Array_UInteger,
   Array_Float, Array_Double,
   Array_FloatComplex, Array_DoubleComplex

'Unsigned' instead of 'U'? XArray instead of Array_X? BTW, is the C
multiarray object going to support all builtin numeric C types? Right
now, there is supported for both signed and unsigned bytes, but not
for unsigned shorts, ints, or longs - is that good enough? 

-Perry Stoll
  Research Associate, CSRL Advanced Telecommunications Research
  2-2 Hikaridai, Seika-cho Soraku-gun, Kyoto 619-02 JAPAN  
  FINGER: stoll@yoshino.atr.co.jp  EMAIL:  stoll@atr-sw.atr.co.jp
PGP 2.6 Key fingerprint = AF 56 5C D8 5F 78 BA FD  21 6E 2A 68 C4 55 9E B0





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

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

From stoll@atr-sw.atr.co.jp  Thu Jan 25 16:33:59 1996
From: stoll@atr-sw.atr.co.jp (Perry A. Stoll)
Date: Fri, 26 Jan 1996 01:33:59 +0900
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: Your message of "Thu, 25 Jan 1996 10:45:58 JST"
References: <9601251545.AA08514@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <199601251633.BAA02667@ciris21.atr-sw.atr.co.jp>

>>>>> "JH" == James Hugunin <jjh@Goldilocks.LCS.MIT.EDU> writes:

    JH>    From: Guido van Rossum <guido@CNRI.Reston.VA.US>

    >> No automatic coercion will take place between these precisions.

    JH>    This surprises me (especially since C does support float ->
    JH> double coercions).  Would you care to explain it?

    JH> Naive users of the system are only expected to use arrays of
    JH> longs, doubles, and complex doubles.  I wanted to make sure
    JH> that all of the automatic coercion rules would work for these
    JH> most frequently used types so that they'll work just like the
    JH> corresponding python scalars.

    JH> On the other hand, I see the other types as being used for
    JH> cases where the programmer really wants to use a particular
    JH> precision, ie. 2-byte integers for dealing with 16-bit sound
    JH> data.  In a case like this it seems decidely unfriendly to
    JH> automatically coerce to another precision.

    JH> One can imagine dividing each sample in a sound by 2, and then
    JH> trying to play it back and hearing garbage because it got
    JH> automatically converted to an array of longs during the
    JH> division.


    JH> I do have one other possible set of rules that I would be
    JH> happy with.  These are basically the same as the last post,
    JH> except:

    JH> 4) Coercion to a higher precision is allowed within the main
    JH> groupings.

    JH> 5) The precision of a python scalar is allowed to change to
    JH> match the other arguments (3.14 can be either a float or a
    JH> double depending on which one is "desired").

    JH> Do people prefer this revised scheme?

So you try to coerce a scalar to the type of the matrix, using
the same idea as in 4)? Is the following right?

Array_SomeIntType   * AnyIntType     =  Array_SomeIntType
Array_SomeIntType   * SomeFloatType  =? Array_SomeFloatType
Array_SomeFloatType * AnyIntType     =? Array_SomeFloatType
Array_SomeFloatType * OtherFloatType =  Array_SomeFloatType

That seems pretty reasonable. Do the '=?' cases sound ok? It should
preserve coercions with the normal Python types. Users of specialized
C type multiarrays must exercise a bit of caution that they don't
cause overflow, but that isn't unreasonable.

-Perry





=================
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  Thu Jan 25 16:27:05 1996
From: guido@CNRI.Reston.VA.US (Guido van Rossum)
Date: Thu, 25 Jan 1996 11:27:05 -0500
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: Your message of "Thu, 25 Jan 1996 10:45:58 EST."
 <9601251545.AA08514@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
References: <9601251545.AA08514@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <199601251627.LAA21529@monty>

>    > No automatic coercion will take place between these precisions.
> 
>    This surprises me (especially since C does support float -> double
>    coercions).  Would you care to explain it?
> 
> Naive users of the system are only expected to use arrays of longs,
> doubles, and complex doubles.  I wanted to make sure that all of the
> automatic coercion rules would work for these most frequently used
> types so that they'll work just like the corresponding python scalars.
> 
> On the other hand, I see the other types as being used for cases where
> the programmer really wants to use a particular precision, ie. 2-byte
> integers for dealing with 16-bit sound data.  In a case like this it
> seems decidely unfriendly to automatically coerce to another
> precision.
> 
> One can imagine dividing each sample in a sound by 2, and then trying
> to play it back and hearing garbage because it got automatically
> converted to an array of longs during the division.

I see your point, but I am uneasy with the solution.  Shouldn't there
be a "divide in place" operation for this case that coerces constants
the other way?  (I haven't followed all the details -- you may have it
already or you may have a good reason for not having it.)

I guess that you also don't check for overflow on such operations --
suppose I multiply each sample by 2 and it doesn't fit...  This is
also different than Python's own numeric operations, but again I can
see the reason why (and I don't object in this case).

I guess I won't complain too loudly as long as you also have a way to
coerce an array of shorts into an array of longs.

(BTW, on 64-bit machines, there are three relevant int sizes.  Do you
support this?)

> I do have one other possible set of rules that I would be happy with.
> These are basically the same as the last post, except:
> 
> 4) Coercion to a higher precision is allowed within the main
> groupings.
> 
> 5) The precision of a python scalar is allowed to change to match the
> other arguments (3.14 can be either a float or a double depending on
> which one is "desired").

Some examples, please?  Where else is coercion applied?  It does sound
like it could be a good compromise.

> I don't like this rule, but without it I think that it is too easy to
> get bitten by python scalars when writing "real" code.

Agreed.

> Does this make sense?
> 
> Do people prefer this revised scheme?

I'm not sure.  More input, please...

--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@Goldilocks.LCS.MIT.EDU  Thu Jan 25 16:40:49 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Thu, 25 Jan 96 11:40:49 EST
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: <199601251633.BAA02667@ciris21.atr-sw.atr.co.jp> (stoll@atr-sw.atr.co.jp)
Message-ID: <9601251640.AA09236@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


   From: "Perry A. Stoll" <stoll@atr-sw.atr.co.jp>

       JH> I do have one other possible set of rules that I would be
       JH> happy with.  These are basically the same as the last post,
       JH> except:

       JH> 4) Coercion to a higher precision is allowed within the main
       JH> groupings.

       JH> 5) The precision of a python scalar is allowed to change to
       JH> match the other arguments (3.14 can be either a float or a
       JH> double depending on which one is "desired").

       JH> Do people prefer this revised scheme?

   So you try to coerce a scalar to the type of the matrix, using
   the same idea as in 4)? Is the following right?

   Array_SomeIntType   * AnyIntType     =  Array_SomeIntType
   Array_SomeIntType   * SomeFloatType  =? Array_SomeFloatType
   Array_SomeFloatType * AnyIntType     =? Array_SomeFloatType
   Array_SomeFloatType * OtherFloatType =  Array_SomeFloatType

   That seems pretty reasonable. Do the '=?' cases sound ok? It should
   preserve coercions with the normal Python types. Users of specialized
   C type multiarrays must exercise a bit of caution that they don't
   cause overflow, but that isn't unreasonable.

   -Perry

This is exactly what I'm proposing (change the '=?' to '=').  The fact
that it seems to make sense to you is a good sign that it might be
reasonable.

-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  Thu Jan 25 16:46:14 1996
From: guido@CNRI.Reston.VA.US (Guido van Rossum)
Date: Thu, 25 Jan 1996 11:46:14 -0500
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: Your message of "Thu, 25 Jan 1996 11:40:49 EST."
 <9601251640.AA09236@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
References: <9601251640.AA09236@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <199601251646.LAA21663@monty>

OK, I'm convinced too.

--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@Goldilocks.LCS.MIT.EDU  Thu Jan 25 16:54:06 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Thu, 25 Jan 96 11:54:06 EST
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: <199601251627.LAA21529@monty> (message from Guido van Rossum on Thu, 25 Jan 1996 11:27:05 -0500)
Message-ID: <9601251654.AA09280@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


   From: Guido van Rossum <guido@CNRI.Reston.VA.US>

   > One can imagine dividing each sample in a sound by 2, and then trying
   > to play it back and hearing garbage because it got automatically
   > converted to an array of longs during the division.

   I see your point, but I am uneasy with the solution.  Shouldn't there
   be a "divide in place" operation for this case that coerces constants
   the other way?  (I haven't followed all the details -- you may have it
   already or you may have a good reason for not having it.)

There should be a divide in place method, I just never bothered to add
it.  I'll try and remedy this before the beta release.

   I guess that you also don't check for overflow on such operations --
   suppose I multiply each sample by 2 and it doesn't fit...  This is
   also different than Python's own numeric operations, but again I can
   see the reason why (and I don't object in this case).

There are in fact two different modules which contain array math
operations.  umath and fast_umath.  These modules will actually define
the code used for things like a*4.  fast_umath will never check for
overflow for the obvious speed reasons.  umath is supposed to work as
much like regular python math as possible.  It checks for
divide-by-zero and for floating point overflows.  At the moment it
doesn't check for integer overflows, but it SHOULD, and it will as
soon as I get around to it.  I think having both of these modules is a
nice way to get "the best of both worlds".

   I guess I won't complain too loudly as long as you also have a way to
   coerce an array of shorts into an array of longs.

Anything can be cast to anything else, including shoving an array of
doubles into an array of bytes.  Of course, some casts are a better
idea than others...

   (BTW, on 64-bit machines, there are three relevant int sizes.  Do you
   support this?)

four actually, byte, short (2-byte), int (4-byte), and long (8-byte).
They're all there.


   > I do have one other possible set of rules that I would be happy with.
   > These are basically the same as the last post, except:
   > 
   > 4) Coercion to a higher precision is allowed within the main
   > groupings.
   > 
   > 5) The precision of a python scalar is allowed to change to match the
   > other arguments (3.14 can be either a float or a double depending on
   > which one is "desired").

   Some examples, please?  Where else is coercion applied?  It does sound
   like it could be a good compromise.

See Perry's recent post for a good explanation of this proposal.

Examples:

array([1,2,3], 'f') * 2. -> array([1,2,3], 'f') # 2. is treated as a float here
array([1,2,3], 'l') * 2. -> array([1,2,3], 'l') # 2. is treated as a double here


   > I don't like this rule, but without it I think that it is too easy to
   > get bitten by python scalars when writing "real" code.

   Agreed.

   > Does this make sense?
   > 
   > Do people prefer this revised scheme?

   I'm not sure.  More input, please...

Well, I just saw your latest reply, so I don't think more input's
needed.  I'll send this anyway because the earlier comments should be
useful.

I think I'll give this thing another hour to settle down and then I'll
code up the new typecasting rules (I really love how quickly
discussion moves on this list).

-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 Jan 25 17:09:17 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Thu, 25 Jan 1996 12:09:17 -0500
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: <9601251545.AA08514@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601251709.MAA13702@cyclone.ERE.UMontreal.CA>


   On the other hand, I see the other types as being used for cases where
   the programmer really wants to use a particular precision, ie. 2-byte
   integers for dealing with 16-bit sound data.  In a case like this it
   seems decidely unfriendly to automatically coerce to another
   precision.

I wouldn't call it "decidedly unfriendly" (you can always avoid
coercion by making sure that all variables have the same type), but it
makes sense. It should also be noted that one of the main reasons to
have float->double coercion in C is to make it possible to call
functions written for double with float arguments. This problem does
not exist in Python.

   4) Coercion to a higher precision is allowed within the main
   groupings.

What are "main groupings"?

   5) The precision of a python scalar is allowed to change to match the
   other arguments (3.14 can be either a float or a double depending on
   which one is "desired").

I don't like this rule for two reasons:
1) You can lose precision without noticing it.
2) It creates a subtle distinction between scalars and arrays of rank 0,
   which can only confuse users.

On the other hand, I do see the problem you want to solve. It doesn't
make any code easier to read if you have to convert every constant to
a rank-0 float array. If I get an ingenious idea for solving this
problem, I'll let you know immediately...

-------------------------------------------------------------------------------
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 Jan 25 17:15:06 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Thu, 25 Jan 1996 12:15:06 -0500
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: <199601251609.BAA02646@ciris21.atr-sw.atr.co.jp> (stoll@atr-sw.atr.co.jp)
Message-ID: <199601251715.MAA14003@cyclone.ERE.UMontreal.CA>


     Also, I don't recall anyone presenting a list of 'nice' names for
   the Matrix functions as Konrad has been advocating. I think having
   these is a good idea; the type code that we have now has always seemed
   somehow counter to (my view of) the Python 'do-it-the-Right-Way'
   attitude.  If I actually list them all out here, maybe this will force
   the issue and start some discussion. Comments on the following?

      Array_Char, Array_UChar
      Array_Short, Array_UShort
      Array_Integer,Array_UInteger,
      Array_Float, Array_Double,
      Array_FloatComplex, Array_DoubleComplex

   'Unsigned' instead of 'U'? XArray instead of Array_X? BTW, is the C

Do we have unsigned types? I proposed a similar list of names a
while ago, using "XArray" instead of "Array_X". I prefer that form
because it is closer to the real-life expressions "integer array",
"float array" etc. But the main point is to get rid of these
silly type codes!

-------------------------------------------------------------------------------
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@Goldilocks.LCS.MIT.EDU  Thu Jan 25 17:28:10 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Thu, 25 Jan 96 12:28:10 EST
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: <199601251709.MAA13702@cyclone.ERE.UMontreal.CA> (hinsenk@ERE.UMontreal.CA)
Message-ID: <9601251728.AA09628@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


   From: hinsenk@ERE.UMontreal.CA (Hinsen Konrad)

      On the other hand, I see the other types as being used for cases where
      the programmer really wants to use a particular precision, ie. 2-byte
      integers for dealing with 16-bit sound data.  In a case like this it
      seems decidely unfriendly to automatically coerce to another
      precision.

   I wouldn't call it "decidedly unfriendly" (you can always avoid
   coercion by making sure that all variables have the same type), but it
   makes sense. It should also be noted that one of the main reasons to
   have float->double coercion in C is to make it possible to call
   functions written for double with float arguments. This problem does
   not exist in Python.

This all is irrelevant if we can agree on the part below.

      4) Coercion to a higher precision is allowed within the main
      groupings.

   What are "main groupings"?

int, float, complex (actually, string is also a grouping, but it
doesn't really pertain).

      5) The precision of a python scalar is allowed to change to match the
      other arguments (3.14 can be either a float or a double depending on
      which one is "desired").

   I don't like this rule for two reasons:
   1) You can lose precision without noticing it.

You can also lose precision by coercing a long to a double, but
nobody's complaining about that.  Also, the only place you can lose
precision is in a python scalar so I'm not really worried about this.
Admittedly, array([1,2,3], 'f')*3.1415926535 might cause you to lose
some precision in pi, but I assume that this is what most people would
want.

   2) It creates a subtle distinction between scalars and arrays of rank 0,
      which can only confuse users.

This is my own objection to the idea, but I think I have a way to make
this cleaner:

Add three more names, "GenericInt", "GenericFloat", "GenericComplex"
(or whatever).

Now I can say a = array(1, "GenericFloat") and this means that in
general a will behave as a double, but it can be coerced downwards to
a float if required.

Now, 3.14 -> array(3.14, "GenericFloat").

Does this seem conceptually clean?

   On the other hand, I do see the problem you want to solve. It doesn't
   make any code easier to read if you have to convert every constant to
   a rank-0 float array. If I get an ingenious idea for solving this
   problem, I'll let you know immediately...

I'm finally starting to feel happy about this proposal, but ingenious
ideas are always welcome.

-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@Goldilocks.LCS.MIT.EDU  Thu Jan 25 17:30:24 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Thu, 25 Jan 96 12:30:24 EST
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: <199601251715.MAA14003@cyclone.ERE.UMontreal.CA> (hinsenk@ERE.UMontreal.CA)
Message-ID: <9601251730.AA09638@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


   From: hinsenk@ERE.UMontreal.CA (Hinsen Konrad)

	Also, I don't recall anyone presenting a list of 'nice' names for
      the Matrix functions as Konrad has been advocating. I think having
      these is a good idea; the type code that we have now has always seemed
      somehow counter to (my view of) the Python 'do-it-the-Right-Way'
      attitude.  If I actually list them all out here, maybe this will force
      the issue and start some discussion. Comments on the following?

	 Array_Char, Array_UChar
	 Array_Short, Array_UShort
	 Array_Integer,Array_UInteger,
	 Array_Float, Array_Double,
	 Array_FloatComplex, Array_DoubleComplex

      'Unsigned' instead of 'U'? XArray instead of Array_X? BTW, is the C

   Do we have unsigned types? I proposed a similar list of names a
   while ago, using "XArray" instead of "Array_X". I prefer that form
   because it is closer to the real-life expressions "integer array",
   "float array" etc. But the main point is to get rid of these
   silly type codes!

Currently the types are:

character
unsigned byte
signed byte
signed short
signed int
signed long
float
double
complex float
complex double

If you really want to add unsigned shorts, longs, and ints, I'd
obviously be willing, but the whole type collection already feels a
little bit large, so I'd rather wait and see if anybody ever NEEDS
them.

-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 Jan 25 18:46:05 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Thu, 25 Jan 1996 13:46:05 -0500
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: <9601251728.AA09628@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601251846.NAA20452@cyclone.ERE.UMontreal.CA>


   You can also lose precision by coercing a long to a double, but
   nobody's complaining about that.  Also, the only place you can lose

That's not exactly the same problem. More importantly, it is
a much less frequent problem.

   precision is in a python scalar so I'm not really worried about this.
   Admittedly, array([1,2,3], 'f')*3.1415926535 might cause you to lose
   some precision in pi, but I assume that this is what most people would
   want.

In this case, with an explicit constant, I agree that most people
would probably want a float result. But suppose you are using a
library function that does float calculations and returns a float
array as a result. You call this function and multiply its result with
a double that you have obtained from some complicated high-precision
calculation. Wouldn't you be both surprised and annoyed if the
result were a float array?

   Add three more names, "GenericInt", "GenericFloat", "GenericComplex"
   (or whatever).

   Now I can say a = array(1, "GenericFloat") and this means that in
   general a will behave as a double, but it can be coerced downwards to
   a float if required.

Why not make it float from the beginning? If you can't rely on the
extra precision being conserved, you could just as well forget about
it. I don't see much use for "unknown precision" numbers.

   Now, 3.14 -> array(3.14, "GenericFloat").

   Does this seem conceptually clean?

Conceptually clean, yes. But it is a somewhat weird concept.


Let me start another approach to the problem: do you see a need for
"downcasting" anything else than constants? In that case one could
think about some special treatment for them.

-------------------------------------------------------------------------------
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 Jan 25 18:48:52 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Thu, 25 Jan 1996 13:48:52 -0500
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: <9601251730.AA09638@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601251848.NAA20609@cyclone.ERE.UMontreal.CA>


   If you really want to add unsigned shorts, longs, and ints, I'd

I didn't mean to suggest that we need more unsigned types!
I just wanted an inventory of existing types for the purpose
of finding names.

   obviously be willing, but the whole type collection already feels a
   little bit large, so I'd rather wait and see if anybody ever NEEDS
   them.

Definitely!

-------------------------------------------------------------------------------
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@Goldilocks.LCS.MIT.EDU  Thu Jan 25 19:01:34 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Thu, 25 Jan 96 14:01:34 EST
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: <199601251846.NAA20452@cyclone.ERE.UMontreal.CA> (hinsenk@ere.umontreal.ca)
Message-ID: <9601251901.AA10739@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


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

      precision is in a python scalar so I'm not really worried about this.
      Admittedly, array([1,2,3], 'f')*3.1415926535 might cause you to lose
      some precision in pi, but I assume that this is what most people would
      want.

   In this case, with an explicit constant, I agree that most people
   would probably want a float result. But suppose you are using a
   library function that does float calculations and returns a float
   array as a result. You call this function and multiply its result with
   a double that you have obtained from some complicated high-precision
   calculation. Wouldn't you be both surprised and annoyed if the
   result were a float array?

I'd be tempted to say that if you have a high-precision double that
you're really concerned about then you'll just have to say something
like pi = array(3.1415926535, 'd').  In general, library functions
should be expected to only return longs, doubles and complex doubles
unless they are somehow "told otherwise".  This is just my opinion.

      Add three more names, "GenericInt", "GenericFloat", "GenericComplex"
      (or whatever).

      Now I can say a = array(1, "GenericFloat") and this means that in
      general a will behave as a double, but it can be coerced downwards to
      a float if required.

   Why not make it float from the beginning? If you can't rely on the
   extra precision being conserved, you could just as well forget about
   it. I don't see much use for "unknown precision" numbers.

The reason to not just make it float is that 3. * Array_l should
produce an array of doubles, not of floats.  Also, if a function can
accept either floats or doubles, 3. should be treated as a double.

      Now, 3.14 -> array(3.14, "GenericFloat").

      Does this seem conceptually clean?

   Conceptually clean, yes. But it is a somewhat weird concept.

Weird I can agree with.

   Let me start another approach to the problem: do you see a need for
   "downcasting" anything else than constants? In that case one could
   think about some special treatment for them.

I don't really see much difference between python scalars and
constants.  The problem with both of them is that they have double
precision no matter what.  I think that it's important to allow these
types to be downcast to a lower precision.  (Or don't allow any
automatic coercion of precision, but that original proposal seems to
be an extremely unpopular idea based on some private responses I've
gotten).

-Jim



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

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

From dubois1@llnl.gov  Thu Jan 25 19:43:31 1996
From: dubois1@llnl.gov (Paul. Dubois)
Date: Thu, 25 Jan 1996 11:43:31 -0800
Subject: [PYTHON MATRIX-SIG] type coercion one more time
References: <9601251759.AA10036@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <3107DD63.7CAB@llnl.gov>

I have been busy giving talks and attending meetings, etc., and had a
hard time plowing through all this carefully. If I understand the latest
idea with respect to precision, I think I can live with it but I don't
like it. It would violate the principle of least surprise. 

It essentially changes the precision of the scalars in Python iff they
get involved with doing something with Array_f's. I don't like
exceptions in languages. Exceptions lead to weird behavior.

For example, we all agree it is a Good Thing that x[i] is a scalar not
an array of size 1. But in fact this means that 
(1./3.) * x[i] is not ((1./3.) * x)[i] if x is Array_f.

I agree it is nice to go fast but let's not go too fast.

I thought the "generic" stuff was off track. Everybody who writes
anything that handles Arrays has enough trouble without one more type to
look for.

Jim, what you need to do in your own work can be pretty much solved with
a little literal function:
def lit(d):
	return Array_f(d)

so that you just always say lit(2.) rather than 2. You have to train
yourself to do this in the places where it matters, true, but otherwise
you are just going to make the rest of us miserable.
-- 
Paul F. Dubois, L-472				(510)-422-5426
Lawrence Livermore National Laboratory		FAX (510)-423-9969
Livermore, CA 94550				dubois1@llnl.gov
Consulting: PaulDubois@aol.com

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

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

From jjh@Goldilocks.LCS.MIT.EDU  Thu Jan 25 21:26:37 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Thu, 25 Jan 96 16:26:37 EST
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: <3107DD63.7CAB@llnl.gov> (dubois1@llnl.gov)
Message-ID: <9601252126.AA12494@baribal.LCS.MIT.EDU.LCS.MIT.EDU>



Paul's and Konrad's arguments make me think that this whole type
coercion issue needs to be reevaluated before mistakenly commiting to
a bad strategy.  I still want to release a 0.30 version tommorrow,
hopefully with stable naming conventions and API.  The only things I
have left to do are packaging and tests on our alphas and pentiums for
some semblance of portability.  Unfortunately, this release will have
an interim API that is highly unlikely to be the final solution, oh
well.


   Sender: dubois@llnl.gov

   I have been busy giving talks and attending meetings, etc., and had a
   hard time plowing through all this carefully. If I understand the latest
   idea with respect to precision, I think I can live with it but I don't
   like it. It would violate the principle of least surprise. 

I agree with this completely.  This is why I proposed the awkward
Array_f*3.14 -> Exception solution.  For me having this go to an
Array_d is not what I am expecting.

   It essentially changes the precision of the scalars in Python iff they
   get involved with doing something with Array_f's. I don't like
   exceptions in languages. Exceptions lead to weird behavior.

   For example, we all agree it is a Good Thing that x[i] is a scalar not
   an array of size 1. But in fact this means that 
   (1./3.) * x[i] is not ((1./3.) * x)[i] if x is Array_f.

This is a great example of where my newer proposal has problems.

   I agree it is nice to go fast but let's not go too fast.

   I thought the "generic" stuff was off track. Everybody who writes
   anything that handles Arrays has enough trouble without one more type to
   look for.

I don't think this will actually impact people much beyond the sort of
problems you mention above.  It's mainly just to keep things
reasonably clean conceptually.

   Jim, what you need to do in your own work can be pretty much solved with
   a little literal function:
   def lit(d):
	   return Array_f(d)

   so that you just always say lit(2.) rather than 2. You have to train
   yourself to do this in the places where it matters, true, but otherwise
   you are just going to make the rest of us miserable.

Well, the last thing I want to do is to make anybody miserable, but I
still think that I have a reasonable point here.

With the current (0.20) type coercion semantics, python scalars are
completely useless in an equation unless you want to work with longs,
doubles, or complex doubles.  The new proposal, while slightly
strange, at least gives a reasonable meaning to python scalars for
other types.

Just to make things concrete, I picked a reasonable simple function
that I use a lot of the time.  Do you find this readable?

def hamming(x):
	return lit(0.54)-lit(0.46)*cos(lit(2*pi)*x/lit(len(x)-1))

vs.

def hamming(x):
	return 0.54-0.46*cos(2*pi*x/(len(x)-1))


-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 Jan 25 19:17:58 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Thu, 25 Jan 1996 14:17:58 -0500
Subject: [PYTHON MATRIX-SIG] type coercion one more time
In-Reply-To: <9601251901.AA10739@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601251917.OAA22980@cyclone.ERE.UMontreal.CA>


   like pi = array(3.1415926535, 'd').  In general, library functions
   should be expected to only return longs, doubles and complex doubles
   unless they are somehow "told otherwise".  This is just my opinion.

Library routines might need floats for the same reason they were
introduced: efficiency. And converting the result to double just
to conform to a specification is a bad idea if the caller wants
to go on using floats.

   The reason to not just make it float is that 3. * Array_l should
   produce an array of doubles, not of floats.  Also, if a function can
   accept either floats or doubles, 3. should be treated as a double.

I understand that, but don't see the point. Either I want double
precision, and then I want it under circumstances, or I am happy
with float, and then I start with float. For what application
might I possible want a number of unknown precision that is as
expensive as double, but can't be trusted to be more than float?
That's the worst of both types.

   I don't really see much difference between python scalars and
   constants.  The problem with both of them is that they have double

Not in implementation, but in use. Most constants occurring in real
programs can be represented by a float, but that is not true for an
arbitrary Python scalar that might be the result of a calculation. So
suppose (in principle; I don't want to do this!) that we add a type
"float" to Python and make all constants that do not exceed the
precision of "float" float constants (with automatic coercion to
double if the need arises), would you say that your problem is solved?

In fact, now that I think of it, this idea is not completely
unrealistic. A new type "float" could be seen as an implementation
alternative to "double" and wouldn't even have to be visible to the
programmer. I'll have to think a bit about this.

   types to be downcast to a lower precision.  (Or don't allow any
   automatic coercion of precision, but that original proposal seems to
   be an extremely unpopular idea based on some private responses I've
   gotten).

Given the choice between the two proposals, I very much prefer the
first one. An occasional exception (whis is easy to fix) is a lot
better than a loss in accuracy without warning.

-------------------------------------------------------------------------------
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 stoll@atr-sw.atr.co.jp  Fri Jan 26 07:37:38 1996
From: stoll@atr-sw.atr.co.jp (Perry A. Stoll)
Date: Fri, 26 Jan 1996 16:37:38 +0900
Subject: [PYTHON MATRIX-SIG] Type coercion two more times
Message-ID: <199601260737.QAA03317@ciris21.atr-sw.atr.co.jp>


I'm about 12 hours behind all of you in North America, so I come to
work in the morning and read all the activity of the previous
day. Most of the debate is over by the time I read it, so I have to
spend the day working instead ;-)

Here's the situation now:
 - There is support for three scalar numerical types in Python:
     PyInteger ( C long )
     PyFloat   ( C double )
     PyComplex ( C double complex )

 - The multiarray object is introducing (providing access to)
   operations for many more C numerical types.

The question is how do we handle operations that mix C numerical types
not in Python (i.e. C float, C short) with Python supported C types (C
long,C double)?

In the following, I'm going to use Jim's term of "3 Classes" of
numerical types ( Integer, Float, Complex) to mean the set of
corresponding C types:

   Integer = any of the C byte,short,int, or long 
   Float   = either C float or C double
   Complex = either C float complex or C double complex

--------------------------------------------------
The Proposal:

We define an optional attribute for multiarrays, say, oh, I don't
know:
       array.__maintain_ctype__, or
       array.__avoid_coercion__, or
       array.__do_no_coerce_me__ (?!?)

- Coercions within a Class (Integer<->Integer,Float<->Float) are
governed by this attribute, namely,
     If this attribute exists and is TRUE:
         then the result will be the same type as the multiarray.
     If the attribute does not exists or is FALSE,
         then NORMAL Python coercion rules apply, and
         the result will always be a PyInteger, PyFloat, or PyComplex.

- Coercions to a higher Class (i.e. Integer-> Float -> Complex) always
occur if necessary. The result will be the normal Python type for that
Class, namely PyInteger, PyFloat, or PyComplex.

- If both operands have this attribute set but the array types
disagree, raise an exception. Operations involving two multiarrays can
be dealt with this way.

- Correspondingly, add a keyword to the Array creation function, i.e.
>>>  myshortarray = Array.array([1,2,3,4],'s',nocoercion=1)

--------------------------------------------------
The Explanation

Normally, this attribute would not be set, so operations will follow
normal Python rules. That makes it consistant with the rest of Python
for new and old users.

But when Jim reads in a C float file, he sets the
"__do_not_coerce_me__" attribute, letting the C multiarray code know
he expects operations involving this array and other Floats to result
in C float arrays.

--------------------------------------------------

Comments?

-Perry




=================
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 Jan 26 14:54:08 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 26 Jan 1996 09:54:08 -0500
Subject: [PYTHON MATRIX-SIG] Type coercion two more times
In-Reply-To: <199601260737.QAA03317@ciris21.atr-sw.atr.co.jp> (stoll@atr-sw.atr.co.jp)
Message-ID: <199601261454.JAA23121@cyclone.ERE.UMontreal.CA>


   I'm about 12 hours behind all of you in North America, so I come to
   work in the morning and read all the activity of the previous

On the contrary, you are 14 hours ahead of us (us on the East coast
at least), so you could complete a whole discussion ready for
us every morning ;-)

   - Coercions within a Class (Integer<->Integer,Float<->Float) are
   governed by this attribute, namely,
	If this attribute exists and is TRUE:
	    then the result will be the same type as the multiarray.
	If the attribute does not exists or is FALSE,
	    then NORMAL Python coercion rules apply, and
	    the result will always be a PyInteger, PyFloat, or PyComplex.

Basically that means having two array types with different behaviour,
and hiding that distinction in an attribute. Which means most users
won't be aware of its existence and will be surprised the first time
they get something else than they expect.

Besides, it doesn't solve Jim's problem of mixing C float arrays with
Python float scalars. If you consider scalars to be of "coercible"
type, then you run into the same problem as with Jim's second
proposal. If not, then the problem is the same as with full automatic
coercion.

-------------------------------------------------------------------------------
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 stoll@atr-sw.atr.co.jp  Fri Jan 26 15:35:12 1996
From: stoll@atr-sw.atr.co.jp (Perry A. Stoll)
Date: Sat, 27 Jan 1996 00:35:12 +0900
Subject: [PYTHON MATRIX-SIG] Type coercion two more times
In-Reply-To: Your message of "Fri, 26 Jan 1996 09:54:08 JST"
References: <199601261454.JAA23121@cyclone.ERE.UMontreal.CA>
Message-ID: <199601261535.AAA03838@ciris21.atr-sw.atr.co.jp>

>>>>> "HK" == Hinsen Konrad <hinsenk@ERE.UMontreal.CA> writes:

    HK> On the contrary, you are 14 hours ahead of us (us on the East

Yes, I realized that this afternoon as I left work for the
weekend. BTW, have a good day at work/school today :-) But don't ask
why I'm logged in after midnight to read this mail :-)

    HK> Basically that means having two array types with different
    HK> behaviour, and hiding that distinction in an attribute. Which

Maybe, but it seems like we're trying to satisfy two conflicting
constraints, namely, 
 1) providing a nice, consistant array library usable for the
mathematically oriented (potential) Python user, and
2) providing easy access to custom, relatively low level number
crunching and control of C types, i.e. 16 bit speech data, 8 bit
images, etc.

    HK> means most users won't be aware of its existence and will be
    HK> surprised the first time they get something else than they
    HK> expect.

Most users won't care about its existance unless they fall into group
2) above. Then they must care about data type conversion and this
provides some degree of control. I'm not saying it's good; this is a
real problem.

    HK> Besides, it doesn't solve Jim's problem of mixing C float
    HK> arrays with Python float scalars.
I thought it did - can you explain this a bit more? I'm probably
missing something. 

    HK> If you consider scalars to be of "coercible" type, then you
    HK> run into the same problem as with Jim's second proposal. 

I see. Yes, the question of whether or not to to convert scalars is
pivotal. If someone is using a type other than a Python numeric
type, then doesn't that mean they are willing to accept the loss of
precision? If you have an array_f, do you expect calculations with
PyFloats to occur at C double precision? I say by using an array_f,
you say "I want C float precision!". 

-Perry




=================
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 Jan 26 15:51:15 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 26 Jan 1996 10:51:15 -0500
Subject: [PYTHON MATRIX-SIG] Type coercion two more times
In-Reply-To: <199601261535.AAA03838@ciris21.atr-sw.atr.co.jp> (stoll@atr-sw.atr.co.jp)
Message-ID: <199601261551.KAA28001@cyclone.ERE.UMontreal.CA>


   Maybe, but it seems like we're trying to satisfy two conflicting
   constraints, namely, 
    1) providing a nice, consistant array library usable for the
   mathematically oriented (potential) Python user, and
   2) providing easy access to custom, relatively low level number
   crunching and control of C types, i.e. 16 bit speech data, 8 bit
   images, etc.

You seem to imply that the additional types will be used only by
people in group 2. But I expect that C floats will also be used by
ordinary mathematically oriented Python users, whenever memory
or CPU time are more important than accuracy. Most of my numerical
programs (mostly in Fortran) use both precisions, so why should
Python code be different?

   I see. Yes, the question of whether or not to to convert scalars is
   pivotal. If someone is using a type other than a Python numeric
   type, then doesn't that mean they are willing to accept the loss of
   precision? If you have an array_f, do you expect calculations with

Sometimes. There are two situations where I expect problems:
1) Someone uses a library written by someone else, and this
   library uses C floats. The user of this library may not be
   aware of this, or might not care. Until he experiences a
   mysterious loss of precision in his code...
2) Someone wants to use both precisions, and either forgets
   about the coercion problems, or expects them to be like in
   all other languages (which coerce float->double, but not
   the reverse).

Therefore I consider Jim's first proposal (no coercion between
float and double) still the best: those who want both precisions
and do everything correctly get what they want, and those who
make a mistake or have misunderstood the rules get an exception.
I'd rather be surprised by an exception than by loss of precision.

-------------------------------------------------------------------------------
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 stoll@atr-sw.atr.co.jp  Fri Jan 26 16:21:57 1996
From: stoll@atr-sw.atr.co.jp (Perry A. Stoll)
Date: Sat, 27 Jan 1996 01:21:57 +0900
Subject: [PYTHON MATRIX-SIG] Type coercion two more times
In-Reply-To: Your message of "Fri, 26 Jan 1996 10:51:15 JST"
References: <199601261551.KAA28001@cyclone.ERE.UMontreal.CA>
Message-ID: <199601261621.BAA03904@ciris21.atr-sw.atr.co.jp>


   You seem to imply that the additional types will be used only by
   people in group 2.

I had been implicitly assuming that. I was basing this on the
precendent set by Python numerical types. 

   Therefore I consider Jim's first proposal (no coercion between
   float and double) still the best: those who want both precisions
   and do everything correctly get what they want, and those who
   make a mistake or have misunderstood the rules get an exception.

Ok, I'm starting to be convinced. My last hurdle to saying yes is
having to explain the following to potential Python array users:
>>> pi = omath.arctan(1.0)*4.0
>>> m = Array_f([1.0,2.0,3.0])
>>> m * pi
Traceback (innermost last):
  File "<stdin>", line 1, in ?
TypeError: inconsistant floating point types

-Perry

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

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

From jjh@Goldilocks.LCS.MIT.EDU  Fri Jan 26 16:28:26 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Fri, 26 Jan 96 11:28:26 EST
Subject: [PYTHON MATRIX-SIG] Type naming conventions
Message-ID: <9601261628.AA00464@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


Returning one last time to the issue of naming conventions.  (I have
some time on my hands until a type coercion strategy is decided on).

I'd like to propose adding the following functions to Numeric.py.

Character
Integer
Float
Complex

On a typical system, Integer(16) would return "s" (the typecode for an
int).

Integer(64) would raise an exception on most systems, but would return
"l" on an alpha.

Thus you could write things like array([1,2,3], Integer(32)).

Things like Integer(minimumSize=16) would also be possible if we
agreed they made sense.  You'd also want to have Integer() just return
the typecode used by python ints.

This could be integrated with the standard array print function to
also have more pleasing outputs.

I know that Paul DuBois had some good comments on this previously in
regards to FORTRAN 90.  I'd be curious to know if this new proposal is
at all useful or reasonable.

Opinions?

-Jim

PS - Thanks to Mike McLay for the note that made me think of this again.

=================
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 Jan 26 16:26:38 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 26 Jan 1996 11:26:38 -0500
Subject: [PYTHON MATRIX-SIG] Type coercion two more times
In-Reply-To: <199601261621.BAA03904@ciris21.atr-sw.atr.co.jp> (stoll@atr-sw.atr.co.jp)
Message-ID: <199601261626.LAA01120@cyclone.ERE.UMontreal.CA>


   Ok, I'm starting to be convinced. My last hurdle to saying yes is
   having to explain the following to potential Python array users:
   >>> pi = omath.arctan(1.0)*4.0
   >>> m = Array_f([1.0,2.0,3.0])
   >>> m * pi
   Traceback (innermost last):
     File "<stdin>", line 1, in ?
   TypeError: inconsistant floating point types

It could be made a bit easier by changing the text of the
error message:
   TypeError: no automatic coercion between precisions

Yet I agree, this is not a desirable feature. It is just the most
acceptable among the evils we have to choose from.

-------------------------------------------------------------------------------
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@Goldilocks.LCS.MIT.EDU  Fri Jan 26 16:35:47 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Fri, 26 Jan 96 11:35:47 EST
Subject: [PYTHON MATRIX-SIG] Type coercion two more times
In-Reply-To: <199601261626.LAA01120@cyclone.ERE.UMontreal.CA> (hinsenk@ere.umontreal.ca)
Message-ID: <9601261635.AA00493@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


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

      Ok, I'm starting to be convinced. My last hurdle to saying yes is
      having to explain the following to potential Python array users:
      >>> pi = omath.arctan(1.0)*4.0
      >>> m = Array_f([1.0,2.0,3.0])
      >>> m * pi
      Traceback (innermost last):
	File "<stdin>", line 1, in ?
      TypeError: inconsistant floating point types

   It could be made a bit easier by changing the text of the
   error message:
      TypeError: no automatic coercion between precisions

   Yet I agree, this is not a desirable feature. It is just the most
   acceptable among the evils we have to choose from.

An important thing to remember here is that a naive user should never
write m = array([1.0,2.0,3.0], 'f') (the new syntax).  They should
just write m = array([1.0,2.0,3.0]) which will produce an array of
doubles and should allow everybody to live happily ever after.

Not that I particularly like the type error either...

-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  Fri Jan 26 16:32:45 1996
From: guido@CNRI.Reston.VA.US (Guido van Rossum)
Date: Fri, 26 Jan 1996 11:32:45 -0500
Subject: [PYTHON MATRIX-SIG] Type coercion two more times
In-Reply-To: Your message of "Sat, 27 Jan 1996 01:21:57 +0900."
 <199601261621.BAA03904@ciris21.atr-sw.atr.co.jp>
References: <199601261551.KAA28001@cyclone.ERE.UMontreal.CA>
 <199601261621.BAA03904@ciris21.atr-sw.atr.co.jp>
Message-ID: <199601261632.LAA25356@monty>

Re confusing Python users: how confusing is Python's use of the words
"float" for "double" and "int" for "long"?  Is it more important to be
consistent with C or with Python?  This may affect the names chosen
for the array types (Array_float, etc.)...

--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 da@maigret.cog.brown.edu  Fri Jan 26 17:03:29 1996
From: da@maigret.cog.brown.edu (David Ascher)
Date: Fri, 26 Jan 1996 12:03:29 -0500 (EST)
Subject: [PYTHON MATRIX-SIG] Type coercion two more times
In-Reply-To: <9601261635.AA00493@baribal.LCS.MIT.EDU.LCS.MIT.EDU> from "James Hugunin" at Jan 26, 96 11:35:47 am
Message-ID: <199601261703.MAA03624@maigret>

>       having to explain the following to potential Python array users:
>       >>> pi = omath.arctan(1.0)*4.0
>       >>> m = Array_f([1.0,2.0,3.0])
>       >>> m * pi
>       Traceback (innermost last):
> 	File "<stdin>", line 1, in ?
>       TypeError: inconsistant floating point types
> 
>    It could be made a bit easier by changing the text of the
>    error message:
>       TypeError: no automatic coercion between precisions

I have no idea whether this is possible or not, but one area where I
think Python needs help is the detail of the exceptions.  For example,
would it be possible at all to have at least the two uncoercable types
listed ("first argument is a single precision float, second argument is
a double precision float")?

--david

PS: This doesn't have to be in the next release, just something to keep
in mind.  A certain set of users at least will want to use the array
tool in an interactive context, where these things matter a lot.



=================
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 Jan 26 17:08:12 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 26 Jan 1996 12:08:12 -0500
Subject: [PYTHON MATRIX-SIG] Type coercion two more times
In-Reply-To: <199601261632.LAA25356@monty> (message from Guido van Rossum on Fri, 26 Jan 1996 11:32:45 -0500)
Message-ID: <199601261708.MAA05505@cyclone.ERE.UMontreal.CA>


   Re confusing Python users: how confusing is Python's use of the words
   "float" for "double" and "int" for "long"?  Is it more important to be
   consistent with C or with Python?  This may affect the names chosen
   for the array types (Array_float, etc.)...

Internal consistency is more important. I don't think of Python as a
dialect of C, and many potential numerical users won't know C at all.

-------------------------------------------------------------------------------
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 Jan 26 17:05:45 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Fri, 26 Jan 1996 12:05:45 -0500
Subject: [PYTHON MATRIX-SIG] Type naming conventions
In-Reply-To: <9601261628.AA00464@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601261705.MAA05321@cyclone.ERE.UMontreal.CA>


   I'd like to propose adding the following functions to Numeric.py.

   Character
   Integer
   Float
   Complex

I like the idea, but would prefer names like CharacterType, IntType etc.
"Integer" looks too much like a cast to integer type.

   Things like Integer(minimumSize=16) would also be possible if we
   agreed they made sense.  You'd also want to have Integer() just return
   the typecode used by python ints.

The latter makes more sense to me.

To be precise, I'd like these functions to return a typecode for a
type that is at least as big as indicated, not necessarily exactly as
big. For integers this is not so important (the sizes are always
8/16/32/64 on modern machines), but there is more variation for float
types. In fact the FloatType() function should perhaps have two
arguments, one specifying precision and the other range. Then
FloatType(10, 50) would specify a type with an accuracy of 10 or more
decimal digits and a range of at least 10**50 (which would be "double"
on most machines, but "float" on a Cray).

-------------------------------------------------------------------------------
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@Goldilocks.LCS.MIT.EDU  Fri Jan 26 23:39:56 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Fri, 26 Jan 96 18:39:56 EST
Subject: [PYTHON MATRIX-SIG] Final pre-beta (0.30) of NumericalPython is available!
Message-ID: <9601262339.AA04290@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


Release 0.30 of the numerical extension to python is available.

Now that the design appears to be final, I'd like as many people as
possible to install this system and play with it.  Once it is released
as 1.0BETA1, any changes to the fundamental design will be very
unlikely to happen, so if you want to have a final system that you'll
be happy with, now's the time to speak up.

You can find the code at:

ftp://sls-ftp.lcs.mit.edu/pub/jjh/NumericalPython-0.30.tar.gz

If somebody (Tom are you there?) would like to place this on a site in
Europe and post the location, I'd appreciate it.  It's frustrating
just how hard it can be to cross the Atlantic these days.

The easiest way to install it is to untar the file in your top level
python directory and follow the instructions in INSTALL.NumPy.  Please
do read this file as it contains important information (unlike the
currently vacuous README).

The naming conventions and C API of this version should be final.  If
this release goes well, the next release will be 1.0BETA1 to the
general python community.  I intend to produce a new bug-fixed release
every week until I manage to go a week without any bug reports, and
then I'll release 1.0BETA, so PLEASE report any bugs you find so that
they can be squashed quickly.

The code is running reasonably stably right now, and I've compilied it
without a problem under the following configurations:

alpha DECOS cc
Sun SUNOS4 gcc 
P90 NextStep3 cc

If you do grab the code and try to compile it, please send me mail
(hugunin@mit.edu) telling me the machine and OS you used, and whether
or not you could get it to compile, and whether or not you could run
the TestSuite (ArrayTest/TestSuite.py).  I'd also like to know the
time reported by the Benchmark in the test suite just out of general
curiosity.

You should also check out TUTORIAL.NumPy for a VERY brief summary of
how to use the object.

Enjoy - Jim




Things that probably will change before the BETA release:

-1 The print function sucks!  There is a function in Numeric.py called
print_array that is the function that gets invoked whenever an array
is printed.  Currently it displays a very ugly representation.  I
really hope that somebody will write a nice pretty printing function
to go here (you get to code it in python instead of C!).

-2 The exact contents of Numeric.py, I'm very interested in comments

-3 The type coercion scheme.  If you only work with longs, doubles,
and complex doubles (the basic python types) you can consider the
coercion scheme fixed and stable.  If you use other types, this is the
current scheme:

Only the following three automatic coercions are allowed:

1) Any integer type can be coerced to a float, a double, a complex float or
a complex double.

2) A float can only be coerced to a complex float.

3) A double can only be coerced to a complex double.

Explanation:

The following type hierarchy is assumed:

INTEGER < FLOAT < COMPLEX

Within each level there are a number of possible precisions.  No
automatic coercion will take place between these precisions.

This remains completely consistent with the existing python automatic
type coercion.

This scheme seems to make the most people the least unhappy, but I'm
still interested in better ideas.


-4 The Precision.py stuff I just coded in the last half hour, so
obviously it might change in the near future.  I am convinced that
something like this is the right approach.

-5 If Jim Fulton implements a nice dynamically loadable version using
CObjects and I can easily install it on my SUNs (I'm usually clueless
about dynamic loading issues) then this will be used.

-6 Now that the design seems stable its time to write documentation.
I'm not enough of a fool to widely release something without decent
documentation.  I've heard rumors that Paul DuBois might be helping
out with this.  Anybody else who'd like to contribute?

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

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

From stoll@atr-sw.atr.co.jp  Sat Jan 27 05:09:12 1996
From: stoll@atr-sw.atr.co.jp (Perry A. Stoll)
Date: Sat, 27 Jan 1996 14:09:12 +0900
Subject: [PYTHON MATRIX-SIG] Final pre-beta (0.30) of NumericalPython is
 available!
In-Reply-To: Your message of "Fri, 26 Jan 1996 18:39:56 JST"
References: <9601262339.AA04290@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <199601270509.OAA04528@ciris21.atr-sw.atr.co.jp>


Being 14 hours ahead may have given me the honor of being the first to 
download and try the code. As usual, being on the cutting edge means
you can get cut, to wit:
 the file Modules/arraytypes.c is NOT IN THE DISTRIBUTION!!! 

I'm trying to use the old matrixtypes.c (converting matrix ->
array). It compiles, but I'll let you know if it works or not...

-Perry

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

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

From jjh@Goldilocks.LCS.MIT.EDU  Sat Jan 27 16:49:14 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Sat, 27 Jan 96 11:49:14 EST
Subject: [PYTHON MATRIX-SIG] Oops!  Problems with 0.30 distribution
Message-ID: <9601271649.AA17704@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


My apologies to all (and thanks to Perry and Konrad for being the guinea
pigs), but I left a file out of the distribution.

This has been fixed now, and the file NumericalPython-0.30.tar.gz should
now contain all of the needed files for a successful compile.

If you've already downloaded the distribution, you can just get the 
file arraytypes.c and put it in your Modules directory.  This is the file
I left out.

I hope this solves the problem - 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@Goldilocks.LCS.MIT.EDU  Sun Jan 28 18:21:22 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Sun, 28 Jan 96 13:21:22 EST
Subject: [PYTHON MATRIX-SIG] New release of NumericPython 0.31
Message-ID: <9601281821.AA06247@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


There turned out to be a small bug in the test suite pertaining to 
complex numbers, so I produced a new release that fixes this.

When untarring the NumericPython release, as well as patches.tar (Konrad's)
patches to the python core), you should use tar -xvfm.  The m tells
tar to set the modification times on the files to the current time, and
this will ensure that a new build will not use old object files.

It was forgetting to do this myself that led to my latest build not including
Konrad's latest patch version, and the bug in the test suite.

For those who don't want to download a complete new version, you just need
to pick up TestCreation.py and put it in ArrayTest.

-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 Jan 29 02:37:00 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Sun, 28 Jan 1996 21:37:00 -0500
Subject: [PYTHON MATRIX-SIG] New release of NumericPython 0.31
In-Reply-To: <9601281821.AA06247@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601290237.VAA05601@cyclone.ERE.UMontreal.CA>


   When untarring the NumericPython release, as well as patches.tar (Konrad's)
   patches to the python core), you should use tar -xvfm.  The m tells
   tar to set the modification times on the files to the current time, and
   this will ensure that a new build will not use old object files.

Also make sure that you remove the old files Lib/Matrix.py and
Lib/MLab.py, otherwise they will be loaded instead of their new
replacements in the directory "numeric". And don't worry if
"TestPrecision" reports bad results; that's just a bug in the test
suite. I got the whole test suite running except for the final speed
benchmark, which uses a function "sum" that no longer exists
(should it?).

-------------------------------------------------------------------------------
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 stoll@atr-sw.atr.co.jp  Mon Jan 29 03:03:10 1996
From: stoll@atr-sw.atr.co.jp (Perry A. Stoll)
Date: Mon, 29 Jan 1996 12:03:10 +0900
Subject: [PYTHON MATRIX-SIG] New release of NumericPython 0.31
In-Reply-To: Your message of "Sun, 28 Jan 1996 21:37:00 JST"
References: <199601290237.VAA05601@cyclone.ERE.UMontreal.CA>
Message-ID: <199601290303.MAA08416@ciris21.atr-sw.atr.co.jp>


>  I got the whole test suite running except for the final speed
> benchmark, which uses a function "sum" that no longer exists
> (should it?)

  Yes, it exists! It's in MLab.py. You have to add 'from MLab import
*' to the top of the Benchmark.py file.

  This means Jim has removed the MLab support from the default Numeric
library. Is this ok with people? I don't mind, but we're going to have
to let people

  Can I make a suggestions: can we avoid the 'from X import *'
construction in the numeric package where it's not speed critical
(??)- it makes finding the source of definitions a pain.

-Perry


=================
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 Jan 29 13:23:36 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Mon, 29 Jan 1996 08:23:36 -0500
Subject: [PYTHON MATRIX-SIG] New release of NumericPython 0.31
In-Reply-To: <199601290303.MAA08416@ciris21.atr-sw.atr.co.jp> (stoll@atr-sw.atr.co.jp)
Message-ID: <199601291323.IAA00117@cyclone.ERE.UMontreal.CA>


     Yes, it exists! It's in MLab.py. You have to add 'from MLab import
   *' to the top of the Benchmark.py file.

Right. I also had to add "from fast_umath import *" to MLab.py,
otherwise it wouldn't know how add.reduce. Note that "from umath import *"
wouldn't work with the benchmark because it produces an overflow:

Traceback (innermost last):
  File "Benchmark.py", line 226, in ?
    test2(10)
  File "Benchmark.py", line 46, in test2
    esc= escout(zt, akap, srcfun)
  File "Benchmark.py", line 115, in escout
    exf= exp(outer(multiply,-1./mu,tau))
OverflowError: math range error

This is of course something the benchmark author should worry about.

     This means Jim has removed the MLab support from the default Numeric
   library. Is this ok with people? I don't mind, but we're going to have
   to let people

I'd have done the same. I see the Matlab compatibility module as
something distinct from the standard array/matrix function, because
the differ in some conventions. Mixing this up would only generate
confusion.

     Can I make a suggestions: can we avoid the 'from X import *'
   construction in the numeric package where it's not speed critical
   (??)- it makes finding the source of definitions a pain.

This is not a matter of speed; the import takes hardly any time.  It
is a matter of typing convenience. It might indeed be a good idea to
to replace this with an explicit list (e.g. "from umath import acos,
asin, atan, ...") in the standard modules, but that should be done
only in the final version, to avoid updating problems.

-------------------------------------------------------------------------------
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  Mon Jan 29 14:43:45 1996
From: friedric@rose.rsoc.rockwell.com (Robin Friedrich)
Date: Mon, 29 Jan 1996 08:43:45 -0600
Subject: [PYTHON MATRIX-SIG] New release of NumericPython 0.31
Message-ID: <199601291443.IAA02517@darwin.rsoc.rockwell.com>


Having a few problems with the Numeric release.
I built 0.30 with tar xvfm as instructed. (I'm not using .31 yet but I don't
think it relates to this problem.)

>From the tutorial:
1)  First problem is with the types.py file. For some reason when it's imported
vars(__builtins__) is an illegal argument while it works fine from the prompt.
Traceback (innermost last):
  File "<stdin>", line 1, in ?
  File "/local2/tools/lib/python/numeric/Numeric.py", line 9, in ?
    import string, types, math
  File "/local2/tools/lib/python/types.py", line 13, in ?
    if vars(__builtins__).has_key('complex'):
TypeError: vars() argument must have __dict__ attribute

2) The following basic function is worrisome as well...

>>> m = Matrix([[1,2,3], [4,5,6], [7,8,9]])
>>> m*m
Traceback (innermost last):
  File "<stdin>", line 1, in ?
  File "/local2/tools/lib/python/numeric/Matrix.py", line 74, in __mul__
NameError: MathError
>>> 

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

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

From stoll@atr-sw.atr.co.jp  Mon Jan 29 15:27:44 1996
From: stoll@atr-sw.atr.co.jp (Perry A. Stoll)
Date: Tue, 30 Jan 1996 00:27:44 +0900
Subject: [PYTHON MATRIX-SIG] New release of NumericPython 0.31
In-Reply-To: Your message of "Mon, 29 Jan 1996 08:43:45 JST"
References: <199601291443.IAA02517@darwin.rsoc.rockwell.com>
Message-ID: <199601291527.AAA10895@ciris21.atr-sw.atr.co.jp>


1) Problem with: if vars(__builtins__).has_key('complex'):
    TypeError: vars() argument must have __dict__ attribute

yep, I had the same problem. The easiest way to get around this and
yet have the same functionality is to comment out the following lines
in $PYLIB/types.py:

#if vars(__builtins__).has_key('complex'):
#        ComplexType = type(complex(0,1))

And add:

try:
        ComplexType = type(complex(0,1))
except:
        pass

I know how  __builtins__ is becoming a dictioary instead of a module
(in Python/ceval.c), but i don't know why. Anyone? Guido?

I don't know about problem 2), although I just tried the same thing ,
namely a matrix multiply, and had got errors. Hey, what would a
prebeta be without a few some problems? :-)

-Perry

=================
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 Jan 29 15:53:34 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Mon, 29 Jan 1996 10:53:34 -0500
Subject: [PYTHON MATRIX-SIG] New release of NumericPython 0.31
In-Reply-To: <199601291443.IAA02517@darwin.rsoc.rockwell.com> (friedric@rose.rsoc.rockwell.com)
Message-ID: <199601291553.KAA09076@cyclone.ERE.UMontreal.CA>


   >From the tutorial:
   1)  First problem is with the types.py file. For some reason when it's imported
   vars(__builtins__) is an illegal argument while it works fine from the prompt.

You can solve this temporarily by removing the call to vars().  It
seems that inside a module definition, __builtins__ is not a module,
but a dictionary. I suspect this is a bug in Python, until someone
can explain me the reason...

   2) The following basic function is worrisome as well...

   >>> m = Matrix([[1,2,3], [4,5,6], [7,8,9]])
   >>> m*m
   Traceback (innermost last):
     File "<stdin>", line 1, in ?
     File "/local2/tools/lib/python/numeric/Matrix.py", line 74, in __mul__
   NameError: MathError
   >>> 

When I try this here, it is a bit different:

Traceback (innermost last):
  File "test.py", line 3, in ?
    m*m
  File "/usr/people/hinsenk/lib/python/numeric/Matrix.py", line 5, in __mul__
    return self.__return_constructor__(self.array.matrixMultiply(other))
AttributeError: __int__

This indicates that some function can't deal with an int matrix.
What puzzles me in your error message is the indication "line 74".
Matrix.py is rather short!

-------------------------------------------------------------------------------
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@Goldilocks.LCS.MIT.EDU  Mon Jan 29 16:21:27 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Mon, 29 Jan 96 11:21:27 EST
Subject: [PYTHON MATRIX-SIG] And onto release 0.32
In-Reply-To: <199601291553.KAA09076@cyclone.ERE.UMontreal.CA> (hinsenk@ere.umontreal.ca)
Message-ID: <9601291621.AA18040@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


The good news is that most of the bugs found so far are extremely
minor, the bad news is that so many small bugs slipped by me on
Friday.

I have a new release that fixes all of the bugs reported so far

Numeric.py lacked some definitions
UserArray and Matrix had a serious bug
small warning in ofuncobject
small bugs in TestSuite
the bug in types.py (which strangely doesn't show up on my system)

ftp://sls-ftp.lcs.mit.edu/pub/jjh/NumericPython-0.32.tar.gz

I'd also like to remind people of Konrad's warning to remove any
previous versions of Matrix.py that might be in your python library
path. 

Similarly, anybody interested in using the new Matrix.py (for linear
algebra style matrices) should take a good long look at Matrix.py.  At
the moment it does almost nothing.  I have no intentions to use this
class personally (a.matrixMultiply(b) works fine for me).  If somebody
sends me a better version of this class I'd be happy to add it to the
distribution.


I know that people probably don't want to keep downloading and
installing a completely new version of the distribution each time some
simple bugs are fixed (the diff's between 0.30 and 0.32 are about 100
lines).  Embarassingly enough, I don't know an easy way to take these
two tar files and produce a diff between them that will be appropriate
for the patch program to be applied to the in-place distribution.
I've included the file "diffs-0.30-0.32" that I made between untarred
directories created from the distribution, if somebody knows how to
take this file and update from 0.30 to 0.32, please share your knowledge.

-Jim


=================
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 Jan 29 17:20:22 1996
From: chris.chase@jhuapl.edu (Chris Chase S1A)
Date: Mon, 29 Jan 1996 12:20:22 -0500
Subject: [PYTHON MATRIX-SIG] Final pre-beta (0.30) of NumericalPython is available!
In-Reply-To: <9601262339.AA04290@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
References: <9601262339.AA04290@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <199601291714.MAA16713@python.org>

>>>>> "JH" == James Hugunin <jjh@Goldilocks.LCS.MIT.EDU> writes:

JH> Release 0.30 of the numerical extension to python is available.

I got it and I am checking it out.  Jim, you announced with the 2.0
release that you would be adding the slice notation patches, i.e. in
the 2.0 release post:

JH> Things I plan to fix ASAP

JH> 1) Integrate Chris Chase's grammar patches to replace
JH>    Slice(None,None,2) with ::2.

JH> 2) Make matrixMultiply work on matrices larger than 2d (this
JH>    requires a notion of rank).

The ":" patch is missing.

I haven't checked yet for extension of matrix multiplication to larger
dimensional arrays.

Are these to be added?

Chris

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

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

From jjh@Goldilocks.LCS.MIT.EDU  Mon Jan 29 17:34:47 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Mon, 29 Jan 96 12:34:47 EST
Subject: [PYTHON MATRIX-SIG] Slice notation and function ranks
In-Reply-To: <9601291713.AA25467@goldilocks> (message from Chris Chase S1A on Mon, 29 Jan 1996 12:20:22 -0500)
Message-ID: <9601291734.AA18476@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


   From: Chris Chase S1A <chris.chase@jhuapl.edu>

   JH> Things I plan to fix ASAP

   JH> 1) Integrate Chris Chase's grammar patches to replace
   JH>    Slice(None,None,2) with ::2.

   JH> 2) Make matrixMultiply work on matrices larger than 2d (this
   JH>    requires a notion of rank).

   The ":" patch is missing.

   I haven't checked yet for extension of matrix multiplication to larger
   dimensional arrays.

   Are these to be added?

I'd still like to do these ASAP, but that "as possible" part is really
getting in my way.

I'm eager to produce a stable, robust, useful version of the array
object that Guido will be happy to include as part of the standard
distribution as quickly as possible.  I think that it would be a very
GOOD THING to have these array objects as a standard module in
Python-1.4.  In the interests of moving this along, I'm unfortunately
neglecting two things that I'd also really like to see done.


1) Better multidimensional indexing (a[:-1, ::2] as well as a[1, .., 2])

Why not?  I don't feel like I have the energy to do the necessary
lobbying to convince the python community/Guido that these changes to
the python core are needed.  I'm using Konrad's patches because he
packaged them up nicely and negociated with Guido for their inclusion
in the next release of the language core.  If somebody (Chris?) can
produce a similar set of patches for slices (okay you've done this
part) AND get Guido to agree to add them to the python core, then I'd
love to incorporate them with the NumericPython package.


2) A solid notion of rank for both bounded and unbounded rank
functions

Why not?  Personally I have no pressing need for this capability (my
own needs for ranks are satisfied by pseudo-indices), and I figure it
would probably take me two-weeks of serious work to do this right and
make sure it's bug free.

Also, this particular feature is an extension to the basic array
system, so it can always be added later without causing any
incompatible changes (I took reasonable care designing the ofuncobject
with such an extension in mind).  This makes me feel more comfortable with
waiting on it until after a solid release 1.0 is out.

-Jim


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

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

From dredish@CS.cmu.edu  Mon Jan 29 18:00:13 1996
From: dredish@CS.cmu.edu (David Redish)
Date: Mon, 29 Jan 1996 13:00:13 -0500
Subject: [PYTHON MATRIX-SIG] Documentation
Message-ID: <19160.822938413@GS151.SP.CS.CMU.EDU>


Is there some documentation available on the Matrix implementation?

Although it seems fast and complete, I've had trouble implementing
even relatively basic operations in v0.2 (such as dot product).  In
v0.3 there is a file TUTORIAL.NumPy but it is rather meager (to say
the least).

Thanks
David Redish		Computer Science Department CMU
graduate student	Neural Processes in Cognition Training Program
			Center for the Neural Basis of Cognition (CNBC)
http://www.cs.cmu.edu/Web/People/dredish/home.html
------------------------------------------------------------
maintainer, CNBC website:
	http://www.cs.cmu.edu/Web/Groups/CNBC
maintainer, Cog-Neuro Sites on the Internet, courtesy CNBC:
	http://www.cs.cmu.edu/Web/Groups/CNBC/other
maintainer, NIPS*96 website:
	http://www.cs.cmu.edu/Web/Groups/NIPS
------------------------------------------------------------

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

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

From jjh@Goldilocks.LCS.MIT.EDU  Mon Jan 29 18:20:43 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Mon, 29 Jan 96 13:20:43 EST
Subject: [PYTHON MATRIX-SIG] Documentation
In-Reply-To: <19160.822938413@GS151.SP.CS.CMU.EDU> (message from David Redish on Mon, 29 Jan 1996 13:00:13 -0500)
Message-ID: <9601291820.AA18632@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


Short answer: Not yet.

If you are confused about how to do something with the array object,
this is the perfect place to ask questions. I'll try and collect the
answers to these questions into the Tutorial (and then when the BETA
release comes out those folks will have a real tutorial).


There are two ways to take the dot product of two vectors a and b.

The first is close to the standard form for writing a dot product:

> add.reduce(a*b)

add.reduce(m) is equivalent to the python form reduce(add, m), but it
will run several orders of magnitude faster for large arrays.

The module Numeric.py also defines the function sum, which is
equivalent to add.reduce, so this could also be written as:

> sum(a*b)


The second approach is to realize that matrixMultiply when applied to
two vectors is equivalent to taking their dot product, so the
following will also work (and will run the fastest):

a.matrixMultiply(b)


-Jim



=================
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 Jan 29 19:02:42 1996
From: chris.chase@jhuapl.edu (Chris Chase S1A)
Date: Mon, 29 Jan 1996 14:02:42 -0500
Subject: [PYTHON MATRIX-SIG] Problem compiling ofuncobject.c
In-Reply-To: <199601291553.KAA09076@cyclone.ERE.UMontreal.CA>
References: <199601291443.IAA02517@darwin.rsoc.rockwell.com>
 <199601291553.KAA09076@cyclone.ERE.UMontreal.CA>
Message-ID: <199601291857.NAA17704@python.org>


While compiling the 0.32 release of the NumericPython I ran into an
error.

Compiling on SGI with IRIX 5.2 and gcc 2.6.0.

I received the following output:

        gcc -O -I./../Include -I.. -DHAVE_CONFIG_H  -c ./ofuncobject.c
./ofuncobject.c: In function `PyOFunc_GenericReduction':
./ofuncobject.c:490: wrong type argument to unary exclamation mark
./ofuncobject.c: In function `PyOFunc_GenericReduceAt':
./ofuncobject.c:590: wrong type argument to unary exclamation mark
*** Error code 1 (bu21)


In ofuncobject.c, lines 490 and 590 have the following:
  if (self->check_return) TRY(check_array(ret));

With TRY defined as:
#define TRY(E) if(! (E)) return NULL

The problem is check_array() has return type void.

I took out the TRY() on those two lines as no action is taken on the
result.

The rest of the compile was successful.

Chris

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

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

From dubois1@llnl.gov  Mon Jan 29 19:00:22 1996
From: dubois1@llnl.gov (Paul. Dubois)
Date: Mon, 29 Jan 1996 11:00:22 -0800
Subject: [PYTHON MATRIX-SIG] Documentation
References: <9601291820.AA18632@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <310D1946.7FF5@llnl.gov>

I have a deadline of Feb. 15 for my article for Computers in Physics in
which I will give the basic documentation for the numerical extension. 
It will exist, trust me. I've been a little late getting it started
because of my work connecting PDB to Python, which is a bottleneck here
for our local work and I just had to push it.

In recent developments, we used Python/Numeric combined with an
extension that can read PDB files and one that knows how to talk to a
fancy graphics package we got from our sister laboratory in France, and
were able to make 3d pictures of the data in the files. (They haven't
made a general release of this package so I won't bother to describe
it).
-- 
Paul F. Dubois, L-472				(510)-422-5426
Lawrence Livermore National Laboratory		FAX (510)-423-9969
Livermore, CA 94550				dubois1@llnl.gov
Consulting: PaulDubois@aol.com

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

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

From dredish@CS.cmu.edu  Mon Jan 29 19:06:51 1996
From: dredish@CS.cmu.edu (David Redish)
Date: Mon, 29 Jan 1996 14:06:51 -0500
Subject: [PYTHON MATRIX-SIG] Compiling on HPUX with gcc
Message-ID: <19315.822942411@GS151.SP.CS.CMU.EDU>


When trying to compile in HPUX with gcc, I get errors on lines 490 and
590 of ofuncobject.c.  The problem is that check_array is of type
void, but TRY() tries to test whether it's 0 or not.  By changing from

	if (self->check_return) TRY(check_array(ret));

to 

	if (self->check_return) check_array(ret);

I can get it to compile.

PS. I see someone just posted this in reference to the SGI.

However, I get a ld error when I try to load it saying unsatisfied
symbol: "finite".

Am I missing a file?

I'm using NumericPython-0.32.tar.gz.  (I also untarred patches.tar.)

Thanks
David Redish		Computer Science Department CMU
graduate student	Neural Processes in Cognition Training Program
			Center for the Neural Basis of Cognition (CNBC)
http://www.cs.cmu.edu/Web/People/dredish/home.html
------------------------------------------------------------
maintainer, CNBC website:
	http://www.cs.cmu.edu/Web/Groups/CNBC
maintainer, Cog-Neuro Sites on the Internet, courtesy CNBC:
	http://www.cs.cmu.edu/Web/Groups/CNBC/other
maintainer, NIPS*96 website:
	http://www.cs.cmu.edu/Web/Groups/NIPS
------------------------------------------------------------


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

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

From jjh@Goldilocks.LCS.MIT.EDU  Mon Jan 29 19:07:37 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Mon, 29 Jan 96 14:07:37 EST
Subject: [PYTHON MATRIX-SIG] Another bug in release 0.32
In-Reply-To: <9601291856.AA26104@goldilocks> (message from Chris Chase S1A on Mon, 29 Jan 1996 14:02:42 -0500)
Message-ID: <9601291907.AA18816@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


I should have known better than to mess around with ofuncobject.c in
the middle of getting out a new release...

For those who haven't been bitten yet, the following patch needs to be
applied to Modules/ofuncobject.c

Basically, on lines 490, and 590, you should remove the TRY from
around the check_array function call.  I have no idea why this didn't
show up as an error under gcc.


*** 487,493 ****
  
    /* Cleanup the returned matrices so that scalars will be returned as python scalars */
  
!   if (self->check_return) check_array(ret);
  
    return PyArray_Return(ret);
  }
--- 487,493 ----
  
    /* Cleanup the returned matrices so that scalars will be returned as python scalars */
  
!   if (self->check_return) TRY(check_array(ret));
  
    return PyArray_Return(ret);
  }
***************


*** 587,593 ****
    Py_DECREF(indices);
  
    /* Cleanup the returned matrices so that scalars will be returned as python scalars */
!   if (self->check_return) check_array(ret);
  
    return PyArray_Return(ret);
  }
--- 587,593 ----
    Py_DECREF(indices);
  
    /* Cleanup the returned matrices so that scalars will be returned as python scalars */
!   if (self->check_return) TRY(check_array(ret));
  
    return PyArray_Return(ret);
  }
***************

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

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

From jjh@Goldilocks.LCS.MIT.EDU  Mon Jan 29 19:22:36 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Mon, 29 Jan 96 14:22:36 EST
Subject: [PYTHON MATRIX-SIG] Compiling on HPUX with gcc
In-Reply-To: <19315.822942411@GS151.SP.CS.CMU.EDU> (message from David Redish on Mon, 29 Jan 1996 14:06:51 -0500)
Message-ID: <9601291922.AA18868@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


   From: David Redish <David_Redish@GS151.SP.CS.CMU.EDU>

<SNIP> stuff about embarassing error covered elsewhere <SNIP>


   However, I get a ld error when I try to load it saying unsatisfied
   symbol: "finite".

   Am I missing a file?


You're not missing a file, you're running into one of the unfortunate
system dependent issues in IEEE libraries.  

On most systems, the standard library includes the function "finite"
which returns true iff a floating point value is not +-Inf, and not
NaN. 

This function is only referenced in ofuncobject.c in the macro CHECK
which is defined at the top of the file.

A quick fix is to just define CHECK(x) as nothing.  This will mean
that the umathmodule will not check for floating point overflows in
calculations as it should.

A better solution would be for you to figure out how to get this
desired behavior on HPUX and send me the patches.

A good check to see if you have a working implementation is to do the
following:

>>> import umath
>>> umath.multiply(1.0e200, 1.0e200)
This should produce OverflowError

If instead it returns Infinity, you know that your routine is not
doing the needed checks.



=================
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 Jan 29 19:49:21 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Mon, 29 Jan 1996 14:49:21 -0500
Subject: [PYTHON MATRIX-SIG] Bug in matrixMultiply, and once more names
Message-ID: <199601291949.OAA01699@cyclone.ERE.UMontreal.CA>

Here's a bug (or two) that I just found:

>>> from Numeric import *
>>> x = array([1,2,3.])
>>> add.reduce(x*x)
14.0
>>> x.matrixMultiply(x)
array(14.0, 'd')
>>> 2.*x.matrixMultiply(x)
Segmentation fault

The segmentation fault is the obvious bug, but I am also surprised
that x.matrixMultiply(x) returns an array of rank 0 instead of a
scalar.

This raises the question of how rank-0 arrays are treated in
general. Although it may seem reasonable to convert them to scalars,
it also makes sense to keep them as arrays if they have one of the new
types (e.g. C float).


About names:

>From the recent discussion I remember that there are supposed to be
two array types: a low-level type "array" and a high-level type
"Array". The latter may have become unnecessary now that "array"s have
automatic coercion again. But should the remaining one be called
"array" or "Array"? I don't really care, but certainly we should have
either "array" and "matrix" or "Array" and "Matrix", not "array" and
"Matrix" as it is now.

Also, I have some more objections against the name of the module
UserArray. I don't like the "UserXxx" names at all (because they don't
relate to the user any more than any other module), but that's not my
point now. UserList is a Python class that is equivalent to the
built-in list type, UserDict similarly wraps dictionaries.  So one
should conclude that UserArray is an analogous wrapping of the old
array type, but that is not true. The new arrays have different
functionality, so they should have another name. One possibility would
be "NumericArray", since the main new feature is numerical
operations. On the other hand, there are no numerical operations on
e.g. character arrays. Maybe someone else finds a better name.

And now back to testing...

-------------------------------------------------------------------------------
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@Goldilocks.LCS.MIT.EDU  Mon Jan 29 20:08:35 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Mon, 29 Jan 96 15:08:35 EST
Subject: [PYTHON MATRIX-SIG] Re: Bug in matrixMultiply, and once more names
In-Reply-To: <199601291949.OAA01699@cyclone.ERE.UMontreal.CA> (hinsenk@ERE.UMontreal.CA)
Message-ID: <9601292008.AA19173@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


   From: hinsenk@ERE.UMontreal.CA (Hinsen Konrad)
   Here's a bug (or two) that I just found:

   >>> from Numeric import *
   >>> x = array([1,2,3.])
   >>> add.reduce(x*x)
   14.0

I assume this isn't a bug.

   >>> x.matrixMultiply(x)
   array(14.0, 'd')

This is a bug all right.  The standing agreement is that all array
functions will return a python scalar instead of a 0d array.  Perhaps
you're right and this should only happen for returned arrays of type
long, double and double complex.  It's all in one function so this
would be an easy change, the final decision on the right thing to do
here depends critically on the decisions made regarding type
coercions.  I just forgot to call this function for matrixMultiply.

   >>> 2.*x.matrixMultiply(x)
   Segmentation fault

I'll fix this too. (once I figure it out)

   About names:

   >From the recent discussion I remember that there are supposed to be
   two array types: a low-level type "array" and a high-level type
   "Array". The latter may have become unnecessary now that "array"s have
   automatic coercion again. But should the remaining one be called
   "array" or "Array"? I don't really care, but certainly we should have
   either "array" and "matrix" or "Array" and "Matrix", not "array" and
   "Matrix" as it is now.

I actually rather like the way that things stand now.  Here's what we
have:

A low level type named array that is what I expect 90% of the people
who use this system to use.  This is entirely implemented in C.

A wrapper class called UserArray that provides a wrapper around this
new built-in array type.  The theory here is that so long as we don't
break any old code, we are free to ignore the old array type as
obsolete.

A subclass of UserArray called Matrix that implements matrixMultiply
instead of array multiply for the "*" operator.  This is mainly
provided for people who do entirely linear algebra work.  Personally I
think that using a.matrixMultiply(b) is a better solution for people
who want to work with both arrays and matrices.

   Also, I have some more objections against the name of the module
   UserArray. I don't like the "UserXxx" names at all (because they don't
   relate to the user any more than any other module), but that's not my
   point now. UserList is a Python class that is equivalent to the
   built-in list type, UserDict similarly wraps dictionaries.  So one
   should conclude that UserArray is an analogous wrapping of the old
   array type, but that is not true. The new arrays have different
   functionality, so they should have another name. One possibility would
   be "NumericArray", since the main new feature is numerical
   operations. On the other hand, there are no numerical operations on
   e.g. character arrays. Maybe someone else finds a better name.

To reiterate, UserArray is a wrapper class around the new C level
type of array.  There is a little bit of baggage in this wrapper
involved in the fact that arrays are a fairly complicated class.  In
fact, I was able to substitute UserArrays into Benchmark.py with
about 10 lines of code as a replacement for arrays, I used this for
testing the speed of the wrapper class.

   And now back to testing...

Keep those bugs 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 et@appl-math.tu-muenchen.de  Mon Jan 29 23:30:20 1996
From: et@appl-math.tu-muenchen.de (Thomas Schwaller)
Date: Tue, 30 Jan 1996 00:30:20 +0100
Subject: [PYTHON MATRIX-SIG] NumericPython-0.32.tar.gz (Europe) + PDE Proposal
Message-ID: <9601300030.ZM28266@hamster.appl-math.tu-muenchen.de>

Yeah. I'm still there...
For people in Europe:
You can fetch the matrixmodule at
ftp://ftp.appl-math.tu-muenchen.de/pub/et/NumericPython-0.32.tar.gz

I was quite happy not to get it more than once (takes really very long).

By the way. Is FDL (or FIDL ?) working with the latest matrixmodule.
(This is rally a question for Jim Fulton ! ;-))
Or asked the other way: is there some work done binding the usual FORTRAN
Libraries (*PACK) to this extension? (To get the state of Matlab, SciLab,
Octave).

Well, let's look one step further. After several experiences with integrating
C++ classes in Python, I'm not that enthousiastic anymore about this approach.
One year earlier I would have tried to do it with Diffpack (C++ classes for
the solution of PDE, which ist one of the best public packages for that
purpose if you like C++). But some native Python Module for that purpose
would be much more efficient, now that we have a common base for matrix
extensions. What about a package for the abstract specification of PDE's?
1) High level commands for building stiffness matrices out of the week form
   of a PDE. This is for expert users. I saw such an abstract matrix
               language (I don't remember the name....) at the International
Congress of        Applied Mathematics.
2) Linear Algebra stuff related to that (Multigrid, Mutlilevel, domain
             decomposition)
3) For non expert users the possibility to solve nonlinear systems of PDE's
   by combining predefinied equations of type 1) (Iteration, Linearization
   and the like)

4) Using the C++ Visual Toolkit as a starting point for the visualisation
   of the results (OpenGL). I had no time to rework my Python Binding for it,
   which is very necessary because it has some bugs. Loading the C++ module
   is very slow so I would prefer to have a native Python/C module using the
   C++ Code (where is code reusing gone ??? :-( ) Unfortunately a lot of work
in    this direction will be done for Java by SGI (read their announcments
   http://www.sgi.com/Products/cosmo).

Some comments?

Anybody written some ODE stuff yet. I took a look at the matlab ODE suite
recently. What a hack... When we present such an example with the official
release of the matrix module, people will like it I think.
I'll polish some Delaunay-Triangulation modules for public release as soon as I
can. They work nice with the matrixmodule, but I have to pythonize the error
handling of the C-Code it uses. For me it's ok, but you will certainly agree
with me, that it's not nice to see the Python interpreter crashing with wrong
geometrical data.

Back to first tests with the new matrix version....


Tom

=================
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 Jan 30 00:19:25 1996
From: jfulton@usgs.gov (Jim Fulton, U.S. Geological Survey)
Date: Mon, 29 Jan 1996 19:19:25 -0500
Subject: [PYTHON MATRIX-SIG] NumericPython-0.32.tar.gz (Europe) + PDE Proposal
In-Reply-To: "Thomas Schwaller" <et@appl-math.tu-muenchen.de>
 "[PYTHON MATRIX-SIG] NumericPython-0.32.tar.gz (Europe) + PDE Proposal" (Jan 30, 12:30am)
References: <9601300030.ZM28266@hamster.appl-math.tu-muenchen.de>
Message-ID: <9601291919.ZM3155@dsdbqvarsa.er.usgs.gov>

On Jan 30, 12:30am, Thomas Schwaller wrote:
> Subject: [PYTHON MATRIX-SIG] NumericPython-0.32.tar.gz (Europe) + PDE Prop
> Yeah. I'm still there...
> For people in Europe:
> You can fetch the matrixmodule at
> ftp://ftp.appl-math.tu-muenchen.de/pub/et/NumericPython-0.32.tar.gz
>
> I was quite happy not to get it more than once (takes really very long).
>
> By the way. Is FDL (or FIDL ?) working with the latest matrixmodule.
> (This is rally a question for Jim Fulton ! ;-))

Not yet.  I've been waiting for the matrix implementation to settle down.
I still have to jump through some hoops before I can release FIDL.

> Or asked the other way: is there some work done binding the usual FORTRAN
> Libraries (*PACK) to this extension? (To get the state of Matlab, SciLab,
> Octave).
>
> Well, let's look one step further. After several experiences with integrating
> C++ classes in Python, I'm not that enthousiastic anymore about this
approach.
> One year earlier I would have tried to do it with Diffpack (C++ classes for
> the solution of PDE, which ist one of the best public packages for that
> purpose if you like C++). But some native Python Module for that purpose
> would be much more efficient, now that we have a common base for matrix
> extensions.

My a "native Python module", do you mean a module written in Python, using the
matrix extension?  Or do you mean a custom built extension?

In what way would this approach be more efficient?

A tool like FIDL allows you to reuse existing libraries with minimal effort.  A
FIDL spec for a routine typically only requires a line or two, not counting
comments.

Jim


=================
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  Tue Jan 30 00:57:54 1996
From: chris.chase@jhuapl.edu (Chris Chase S1A)
Date: Mon, 29 Jan 1996 19:57:54 -0500
Subject: [PYTHON MATRIX-SIG] Compiling on HPUX with gcc
In-Reply-To: <9601291922.AA18868@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
References: <19315.822942411@GS151.SP.CS.CMU.EDU>
 <9601291922.AA18868@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <199601300052.TAA20689@python.org>


   From: David Redish <David_Redish@GS151.SP.CS.CMU.EDU>

<SNIP> stuff about embarassing error covered elsewhere <SNIP>


   However, I get a ld error when I try to load it saying unsatisfied
   symbol: "finite".

   Am I missing a file?

HPUX series 700/800 at Release 9 contain two versions of the math
library.  The precision architecture (PA) libm version 1.1 contains
the IEEE functions.  It is located in /lib/pa1.1.  By default gcc
links against version 1.0 (in /lib) whereas HPUX cc links against
version 1.1.

If you have the pa1.1 libraries then use the --with-libm=-L/lib/pa1.1
option to configure to get the pa1.1 version of libm when using gcc.
Using this I was able to compile successfully.  An aside:
/usr/lib/pa1.1 for the library path when using FORTRAN or PASCAL or
the vector library.  Of possible future interest, the vector library
on the HP series 700 systems is very fast and contains a number of
operations that Numeric module could use for many of its basic
operations.

Another note: I have been unable to get Python to compile with the HP
C compiler with or without ANSI mode.

Chris


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

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

From stoll@atr-sw.atr.co.jp  Tue Jan 30 02:57:23 1996
From: stoll@atr-sw.atr.co.jp (Perry A. Stoll)
Date: Tue, 30 Jan 1996 11:57:23 +0900
Subject: [PYTHON MATRIX-SIG] A fix for mrange
Message-ID: <199601300257.LAA12363@ciris21.atr-sw.atr.co.jp>



>>> Numeric.mrange(1,5,1,'i')
Traceback (innermost last):
  File "<stdin>", line 1, in ?
  File "/home/stoll/Python/1.3/lib/python/numeric/Numeric.py", line 64, in mrange
    return m*step + start
TypeError: cannot perform this operation on these types
>>> Numeric.mrange(1,5,0.5,'f')
Traceback (innermost last):
  File "<stdin>", line 1, in ?
  File "/home/stoll/Python/1.3/lib/python/numeric/Numeric.py", line 64, in mrange
    return m*step + start
TypeError: cannot perform this operation on these types

>>> Numeric.mrange(1,5,1.0,'l')
array([1.0,2.0,3.0,4.0], 'd')


Shouldn't mrange honor the typecode?

How about this as a replacement for mrange:

# ???default typecode to long int to match builtin range()???
def mrange(start, stop=None, step=1, typecode='l'):
	"""Just like range() except it returns an array whose
	type can be specfied by the keyword argument typecode.
	"""

	if (stop == None):
		stop = start
		start = 0
	n = int(math.ceil(float(stop-start)/step))
 	m = array(range(n), 'l')*step + start
 	if (m.typecode() != typecode):
 	     m = m.cast(typecode)
 	return m


Now I get this:
>>> Numeric.mrange(1,5,1,'i')
array([1,2,3,4], 'i')
>>> Numeric.mrange(1,5,1.0,'l')
array([1,2,3,4], 'l')
>>> Numeric.mrange(200,300,10,'b')
array([200,210,220,230,240,250,4,14,24,34], 'b')
>>> Numeric.mrange(1,5,0.25,'l')
array([1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4], 'l')

The last is a little weird, but mrange always honors the typecode,
which I think is very important. When I specify a type, I expect an
array of that type.

To coerce or not to coerce, that is the question...

-Perry

=================
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 Jan 30 13:39:04 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 30 Jan 1996 08:39:04 -0500
Subject: [PYTHON MATRIX-SIG] First experiences
Message-ID: <199601301339.IAA22977@cyclone.ERE.UMontreal.CA>

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

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

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

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

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

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

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

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

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

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

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

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

-------------------------------------------------------------------------------
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 da@maigret.cog.brown.edu  Tue Jan 30 15:30:50 1996
From: da@maigret.cog.brown.edu (David Ascher)
Date: Tue, 30 Jan 1996 10:30:50 -0500 (EST)
Subject: [PYTHON MATRIX-SIG] None, All, etc.
In-Reply-To: <199601301339.IAA22977@cyclone.ERE.UMontreal.CA> from "Hinsen Konrad" at Jan 30, 96 08:39:04 am
Message-ID: <199601301530.KAA18459@maigret>

After just reading Hinsen's post, and remembering Jim H's, comments
about 'this is the perfect place to ask', I'd like to ask one question 
which I'm sure many novices will have.  A good answer to this one should
be in the Tutorial.  [Stealing from APL/J docs is a possible way to go]

What are these pseudo-indices (None, All, etc.) and how do they work?

--david

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

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

From jjh@Goldilocks.LCS.MIT.EDU  Tue Jan 30 16:12:04 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Tue, 30 Jan 96 11:12:04 EST
Subject: [PYTHON MATRIX-SIG] Re: A fix for mrange
In-Reply-To: <199601300257.LAA12363@ciris21.atr-sw.atr.co.jp> (stoll@atr-sw.atr.co.jp)
Message-ID: <9601301612.AA03369@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


  Shouldn't mrange honor the typecode?

Obviously, I'll switch over to using your new version.  However, I
think that it's important to make a small change for determining the
default typecode.  If any of the arguments is a python float, than the
range returned should be an array of doubles, not longs.

ie. arange(1, 5, 1.0) should be array([1.,2.,3.,4.], 'd')

I'll add some checks to the code to get this behavior in the case of
no explicit typecode given.

BTW - the typecode argument is really intended to be used as a keyword
argument, as in arange(1, 5, 1.0, typecode=Integer()).  This keeps
things uniform for the case of arange(10, typecode=Integer()) which
wouldn't work without the keyword argument.

  The last is a little weird, but mrange always honors the typecode, 
  which I think is very important. When I specify a type, I expect an
  array of that type.

Agreed!

  To coerce or not to coerce, that is the question...

Now that question needs to be addressed seperately.

Thanks for the fix - 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@Goldilocks.LCS.MIT.EDU  Tue Jan 30 16:35:08 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Tue, 30 Jan 96 11:35:08 EST
Subject: [PYTHON MATRIX-SIG] First experiences
In-Reply-To: <199601301339.IAA22977@cyclone.ERE.UMontreal.CA> (hinsenk@ere.umontreal.ca)
Message-ID: <9601301635.AA03443@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Easy to fix.

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

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

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

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

Try this:

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

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

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

-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@Goldilocks.LCS.MIT.EDU  Tue Jan 30 17:42:49 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Tue, 30 Jan 96 12:42:49 EST
Subject: [PYTHON MATRIX-SIG] Pseudo Indices
In-Reply-To: <199601301530.KAA18459@maigret> (da@maigret.cog.brown.edu)
Message-ID: <9601301742.AA03714@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


Well, here's a fairly long and slightly confusing response, but what
do you expect from a first draft?


The idea of pseudo indices comes from the language Yorick created by
Dave Munro at LLNL, not from APL/J.


Everybody expects this to work:
a = array([1,2,3])

a+2 -> array([3,4,5])

2 is 0-dimensional array with shape [], and a has shape [3].  The rule
says that any non-existent dimension is "broadcast" to match a higher
dimensional array as required.

The idea is to extend this notion of broadcasting to any dimension of
length one.  So the following will also work:

a+array([2]) -> array([3,4,5])

array([2]) has shape [1], and a has shape [3].  The [1] is broadcast
to match the [3].

The classic example of where this is useful is in taking an
outer product.

b = array([10, 20])

a * b.reshape(2, 1) -> array([[11, 12, 13], [21, 22, 23]])

a has shape [3], and b.reshape(2,1) has shape [2, 1].  The result of a binary
operator applied to them has shape [2,3].


In order to make such code easier to read, Yorick introduces the
notion of a pseudo index that can be added to any multidimensional index
and means, add a new dimension here.

ie. b[2, PseudoIndex] <--> b.reshape(2, 1)

"All" is not in fact related to Yorick pseudo indices at all, but is
related to Slices.

c = array([[1,2,3], [11,12,13]])

I'd really like to be able to say c[:, 3] -> array([3,13]).  Python
syntax doesn't currently allow this, so until somebody convinces Guido
to make the change, the following objects are used instead.

c[:, 1:2] --> c[Slice(), Slice(1,2)]

All = Slice()

One more piece is needed to handle multidimensional indexing properly.
Let's say that I want to extract the third element from the last
dimension of an array.

In Yorick that would look like a[.., 3].  Since Python doesn't yet
have this rubber index, I use the following:

a[RubberIndex, 3].

So, the following special symbols are needed to properly treat
multidimensional indexing:

Slice
PseudoIndex
RubberIndex

My current feeling on the best way to do this is to keep Slice's as
they are (until somebody lobbys Guido for a better system).

Define string constants

NewAxis = "NewAxis" 
Ellipses = "Ellipses"

NewAxis is equivalent to the current "None" and indicates a
PseudoIndex

Ellipses is equivalent to the current "RubberIndex" and indicates
standard ellipses as in, fill in what should naturally go here.

Comments?

-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@Goldilocks.LCS.MIT.EDU  Tue Jan 30 17:54:22 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Tue, 30 Jan 96 12:54:22 EST
Subject: [PYTHON MATRIX-SIG] First experiences
In-Reply-To: <199601301726.MAA16169@cyclone.ERE.UMontreal.CA> (hinsenk@ERE.UMontreal.CA)
Message-ID: <9601301754.AA03750@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


   From: hinsenk@ERE.UMontreal.CA (Hinsen Konrad)

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

   In the spirit of "no needless redundancies", it would be better not to
   have this function. Maybe we should add an (optional) module with
   standard abbreviations, where we would simply write sum =
   add.reduce. That would also be a good way to have clearer standard
   names for things like arange() while still having short alternatives
   that are available on every system.

I think I like this idea, I'll play with it and see what I come up with.

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

   It could still return a new pointer if the size is the same,
   and make a copy only if the size changes. Personally I don't care

This I REALLY don't want.  I firmly believe that whether a function
returns a pointer or a copy should not be dependent on its arguments.

   about dimension checking; in all my APL code that has never been
   a problem. If the size remains the same, then typically the
   new dimensions are specified as an expression involving the old
   dimensions. I have never had an error there.

      Try this:

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

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

   Not really. First of all, in most cases I need a non-destructive
   version, similar to sequence addition. Second, I really need
   it for all dimensions. In my application, I have two 1d arrays
   of equal length and have to construct a 2d array from them.
   What I used is
      c = array([tuple(a), tuple(b)])
   but there ought to be a much cleaner and more efficient way.

Well, you should use c = array([a, b]) for that.  This seems fairly
clean to me, and will run quite efficiently if a and b are already
arrays of the same type.

What do you mean by non-destructive?  a.concat(b) does not modify a,
but instead returns a new array that is b concatenated with a.  This
is almost exactly equivalent to a+b if a and b were lists.

   BTW, we also ought to have a way to convert arrays to nested
   lists and maybe tuples. Oddly enough, Python has no built-in
   function list(), although it does have tuple().

I agree, I'll add this when I get the time.  I'll probablyu call it
toList() to go along with toString and toFile.

      It should probably work along any axis, but I don't have a terribly
      good way to specify the axis and still keep the nice feature of being
      able to concat together an arbitrary number of arrays (very important

   One argument could be a tuple of all arrays to be concatenated.

This doesn't work nicely if you only have one array.

      for efficiency).  It would also be a bit of a hassle to write in C the
      way you're suggesting, would it be enough to add in a standard python
      function with the desired behavior?

   That's just a matter of efficiency and has to be tried. In my APL code
   this function is used a lot, and often on small arrays.

Again, what would you call this new method?

-Jim



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

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

From dubois1@llnl.gov  Tue Jan 30 18:05:22 1996
From: dubois1@llnl.gov (Paul. Dubois)
Date: Tue, 30 Jan 1996 10:05:22 -0800
Subject: [PYTHON MATRIX-SIG] Uniform random number generator v. 2.0
Message-ID: <310E5DE2.5E40@llnl.gov>

On ftp-icf.llnl.gov, directory /pub/basis, lies:
URNG-2.0.tar.gz
which contains a C extension and Python wrapper for a random number
generator equivalent to the one on Cray systems. This version works with
the Numeric extension 0.32. (It contains a feature for returning a
random sample or randomly-filled array of arbitrary shape, as well as a
more pedestrian "ranf()".)

URNG can create separate generators that act independently for use in
different modules.

Note to Jim Hugunin: I can't remember how I "delivered" this to your ftp
directory before...
-- 
Paul F. Dubois, L-472				(510)-422-5426
Lawrence Livermore National Laboratory		FAX (510)-423-9969
Livermore, CA 94550				dubois1@llnl.gov
Consulting: PaulDubois@aol.com

=================
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  Tue Jan 30 18:09:42 1996
From: guido@CNRI.Reston.VA.US (Guido van Rossum)
Date: Tue, 30 Jan 1996 13:09:42 -0500
Subject: [PYTHON MATRIX-SIG] Pseudo Indices
In-Reply-To: Your message of "Tue, 30 Jan 1996 12:42:49 EST."
 <9601301742.AA03714@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
References: <9601301742.AA03714@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
Message-ID: <199601301809.NAA08602@monty>

> ie. b[2, PseudoIndex] <--> b.reshape(2, 1)

I'm not sure I understand reshape completely, but isn't this a rather
drastic reinterpretation of the index arguments when a pseudo index is
present?  In general, if no pseudo index is present, single indices
take away that dimension, don't they?  (While slice indices can reduce
the length in that dimension but otherwise leave it intact.)  But in
your example, the '2' becomes a shorthand for a slice.  I don't like
this very much...

> I'd really like to be able to say c[:, 3] -> array([3,13]).  Python
> syntax doesn't currently allow this, so until somebody convinces Guido
> to make the change, the following objects are used instead.

Same comment -- I don't like the '3' index to turn into a slice by
context, if I understand this right.  (Bear with me, I'm not even sure
that array([3, 13]) really is a 3x13 matrix.)

> c[:, 1:2] --> c[Slice(), Slice(1,2)]

This is fine (and what I thought you were proposing all the time).  I
would consider a patch if the existing 1-dim sequence and mapping
types are not affected.

> a[RubberIndex, 3].

You could sneak this into the abovementioned patch as "a[::, 3]".

> (until somebody lobbys Guido for a better system).

Ain't I nice today? ;-)

--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@Goldilocks.LCS.MIT.EDU  Tue Jan 30 18:13:06 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Tue, 30 Jan 96 13:13:06 EST
Subject: [PYTHON MATRIX-SIG] Uniform random number generator v. 2.0
In-Reply-To: <310E5DE2.5E40@llnl.gov> (dubois1@llnl.gov)
Message-ID: <9601301813.AA03881@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


  Note to Jim Hugunin: I can't remember how I "delivered" this to your ftp
  directory before...

Our sysadmins plugged a security hole that had made it so convenient
for people to upload code like this to my ftp directory in the past.
Since I still like the idea of keeping things like this in one place,
I'll take it on myself to download code like this to
sls-ftp.lcs.mit.edu into directory /pub/jjh.

This is already done for Paul's URNG package.

-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@Goldilocks.LCS.MIT.EDU  Tue Jan 30 18:34:54 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Tue, 30 Jan 96 13:34:54 EST
Subject: [PYTHON MATRIX-SIG] Pseudo Indices
In-Reply-To: <199601301809.NAA08602@monty> (message from Guido van Rossum on Tue, 30 Jan 1996 13:09:42 -0500)
Message-ID: <9601301834.AA03955@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


   From: Guido van Rossum <guido@CNRI.Reston.VA.US>

   > ie. b[2, PseudoIndex] <--> b.reshape(2, 1)

   I'm not sure I understand reshape completely, but isn't this a rather
   drastic reinterpretation of the index arguments when a pseudo index is
   present?  In general, if no pseudo index is present, single indices
   take away that dimension, don't they?  (While slice indices can reduce
   the length in that dimension but otherwise leave it intact.)  But in
   your example, the '2' becomes a shorthand for a slice.  I don't like
   this very much...

I'm sorry, that was a type-o on my part.  What I should have said was
b[All, PseudoIndex] <--> b.reshape(2,1).

   > I'd really like to be able to say c[:, 3] -> array([3,13]).  Python
   > syntax doesn't currently allow this, so until somebody convinces Guido
   > to make the change, the following objects are used instead.

   Same comment -- I don't like the '3' index to turn into a slice by
   context, if I understand this right.  (Bear with me, I'm not even sure
   that array([3, 13]) really is a 3x13 matrix.)

Here you are simply not understanding my (admittedly poor)
description.  array([3,13]) is a one dimensional array with a shape of
[2] which contains the numeric elements 3 and 13.  So the 3 index is
not returning a slice by context.  The returned array has a dimension
one less that the initial array because it has the index 3 instead of
a slice.

   > c[:, 1:2] --> c[Slice(), Slice(1,2)]

   This is fine (and what I thought you were proposing all the time).  I
   would consider a patch if the existing 1-dim sequence and mapping
   types are not affected.

Great!  I'll get on with the process of coordinating this patch.

Currently the best way we've come up to implement this patch is to add
a new object type to python called a sliceobject.  c[:, 1:2] then gets
converted to c[ (slice(), slice(1,2)) ] in the interpreter and then
passed to the standard getitem mapping method.  Special consideration
is payed to c[:] so as not to break existing code.  

I'm a little bit troubled by the need to add a new object (admittedly
extremely small) just to get this behavior.  Does this solution
seem reasonable to you?

The only other approach I can think of is to add a new protocol for
multidimensional arrays, on equal footing with number, mapping, and
sequence.  This seems like it would be overkill.

   > a[RubberIndex, 3].

   You could sneak this into the abovementioned patch as "a[::, 3]".

Slices have an additional feature which is a third index specifying
a stride.  ie. Slice(None,None,2) will take all the even elements
along a dimension.  Slice(None,None,-1) will reverse a dimension.
This arrangement corresponds very nicely with the internals of array
objects.

Unfortunately, this means that things like ::-1 will be reasonably
common, and so using :: as a RubberIndex might be confusing.

However, I do like this syntax for the RubberIndex as it really
captures what it does which is to apply : to every unused dimension.
Maybe there's a similar proposal that will work.

   > (until somebody lobbys Guido for a better system).

   Ain't I nice today? ;-)

Gee, now that we've got Guido in such a friendly mood, what else
should we ask for?  A new operator just for matrix multiplication? ;)

-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 Jan 30 19:21:11 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 30 Jan 1996 14:21:11 -0500
Subject: [PYTHON MATRIX-SIG] Re: Pseudo Indices
In-Reply-To: <9601301742.AA03714@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601301921.OAA23872@cyclone.ERE.UMontreal.CA>


   In order to make such code easier to read, Yorick introduces the
   notion of a pseudo index that can be added to any multidimensional index
   and means, add a new dimension here.

   ie. b[2, PseudoIndex] <--> b.reshape(2, 1)

Not quite. "2" means "the third element".

   "All" is not in fact related to Yorick pseudo indices at all, but is
   related to Slices.

But "All" is the equivalent of the Yorick pseudoindex *, which of
course is also a special form of a slice.

   c = array([[1,2,3], [11,12,13]])

   I'd really like to be able to say c[:, 3] -> array([3,13]).  Python

Small correction: c[:, 2].

   In Yorick that would look like a[.., 3].  Since Python doesn't yet
   have this rubber index, I use the following:

   a[RubberIndex, 3].

That should also get a better name... I think I already made
some proposals, I just have to dig that message out again...

-------------------------------------------------------------------------------
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  Tue Jan 30 19:33:41 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 30 Jan 1996 14:33:41 -0500
Subject: [PYTHON MATRIX-SIG] First experiences
In-Reply-To: <9601301754.AA03750@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601301933.OAA24990@cyclone.ERE.UMontreal.CA>


      It could still return a new pointer if the size is the same,
      and make a copy only if the size changes. Personally I don't care

   This I REALLY don't want.  I firmly believe that whether a function
   returns a pointer or a copy should not be dependent on its arguments.

You are right. I had forgotten that returning a pointer or returning
a copy makes a real difference here; I am probably too much infected
by J, in which arrays are immutable objects. And the more I think
about it, the more I like immutable arrays! But that's another point.

   Well, you should use c = array([a, b]) for that.  This seems fairly
   clean to me, and will run quite efficiently if a and b are already
   arrays of the same type.

I didn't know this was possible (of course I should have tried...).
But still that is a solution only if I want to create a new first
axis. What if I don't want a new axis, or if the new axis is not
the first one?

   What do you mean by non-destructive?  a.concat(b) does not modify a,
   but instead returns a new array that is b concatenated with a.  This
   is almost exactly equivalent to a+b if a and b were lists.

OK, I misunderstood this.

      One argument could be a tuple of all arrays to be concatenated.

   This doesn't work nicely if you only have one array.

Not as long as it is a method. But concat() could be made a normal
function. Actually, that is another slightly unclear point in the
current array module. Some operations are functions (e.g. reshape()),
others are methods (like concat()), but that seems to be completely
arbitrary.

      That's just a matter of efficiency and has to be tried. In my APL code
      this function is used a lot, and often on small arrays.

   Again, what would you call this new method?

Ehh... Which one? Concatenation? Well, I still hope to find
a solution that incorporates all applications into one, which
can then be called concat(). We should try to keep the number
of functions/methods to a minimum. So how about this:

function concat((a,b,c...), n=0)
  concatenates arrays a,b,c,... along the nth axis and returns
  the result. The shape along the other axes must agree.

This doesn't take care of new axes, but they can be added
easily with the pseudo index.

-------------------------------------------------------------------------------
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@Goldilocks.LCS.MIT.EDU  Tue Jan 30 19:50:41 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Tue, 30 Jan 96 14:50:41 EST
Subject: [PYTHON MATRIX-SIG] First experiences
In-Reply-To: <199601301933.OAA24990@cyclone.ERE.UMontreal.CA> (hinsenk@ERE.UMontreal.CA)
Message-ID: <9601301950.AA04262@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


   From: hinsenk@ERE.UMontreal.CA (Hinsen Konrad)

   You are right. I had forgotten that returning a pointer or returning
   a copy makes a real difference here; I am probably too much infected
   by J, in which arrays are immutable objects. And the more I think
   about it, the more I like immutable arrays! But that's another point.

I rather like immutable arrays myself, but I was convinced that
mutable arrays were the right choice sometime in the middle of this
project, and I'm unlikely to change again.

   current array module. Some operations are functions (e.g. reshape()),
   others are methods (like concat()), but that seems to be completely
   arbitrary.

Actually, reshape is now an array method, and the old reshape function
is only around for "historical reasons".  I should probably remove it.

	 That's just a matter of efficiency and has to be tried. In my APL code
	 this function is used a lot, and often on small arrays.

      Again, what would you call this new method?

   Ehh... Which one? Concatenation? Well, I still hope to find
   a solution that incorporates all applications into one, which
   can then be called concat(). We should try to keep the number
   of functions/methods to a minimum. So how about this:

   function concat((a,b,c...), n=0)
     concatenates arrays a,b,c,... along the nth axis and returns
     the result. The shape along the other axes must agree.

   This doesn't take care of new axes, but they can be added
   easily with the pseudo index.

This can easily be added to the standard set of functions and
implemented on top of the existing transpose and concat methods.  You
might want to do this as an exercise ;).  

I was actually asking for a new name for the method that will do a
reshape allowing you to make copies of the array in the process.  I'm
fairly convinced that I don't want this to be the default behavior of
the reshape method.

-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 Jan 30 20:00:59 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 30 Jan 1996 15:00:59 -0500
Subject: [PYTHON MATRIX-SIG] Pseudo Indices
In-Reply-To: <199601301809.NAA08602@monty> (message from Guido van Rossum on Tue, 30 Jan 1996 13:09:42 -0500)
Message-ID: <199601302000.PAA26746@cyclone.ERE.UMontreal.CA>


   > c[:, 1:2] --> c[Slice(), Slice(1,2)]

   This is fine (and what I thought you were proposing all the time).  I
   would consider a patch if the existing 1-dim sequence and mapping
   types are not affected.

What do you mean by "not affected"? That their semantics stays
the same (no problem) or that their implementation needn't
be changed? I am not sure the latter is possible for C-types.

   > a[RubberIndex, 3].

   You could sneak this into the abovementioned patch as "a[::, 3]".

I like that idea...

If I had enough time, I'd look at this, but that might not happen
for a while. Any other volunteers?

-------------------------------------------------------------------------------
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@Goldilocks.LCS.MIT.EDU  Tue Jan 30 20:26:30 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Tue, 30 Jan 96 15:26:30 EST
Subject: [PYTHON MATRIX-SIG] Pseudo Indices
In-Reply-To: <199601302000.PAA26746@cyclone.ERE.UMontreal.CA> (hinsenk@ERE.UMontreal.CA)
Message-ID: <9601302026.AA04461@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


   From: hinsenk@ERE.UMontreal.CA (Hinsen Konrad)

      > c[:, 1:2] --> c[Slice(), Slice(1,2)]

      This is fine (and what I thought you were proposing all the time).  I
      would consider a patch if the existing 1-dim sequence and mapping
      types are not affected.

   What do you mean by "not affected"? That their semantics stays
   the same (no problem) or that their implementation needn't
   be changed? I am not sure the latter is possible for C-types.

Chris Chase actually has a prototype implementation that doesn't alter
the implementation for C types.  Basically it special cases these calls.

      > a[RubberIndex, 3].

      You could sneak this into the abovementioned patch as "a[::, 3]".

   I like that idea...

   If I had enough time, I'd look at this, but that might not happen
   for a while. Any other volunteers?

Again, Chris Chase has a good starting point for an implementation of
this.  I'll probably polish it up myself (unless I can talk him into
spending some more time on it) and add it to the NumericPython
distribution for testing.

-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 Jan 30 20:43:22 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 30 Jan 1996 15:43:22 -0500
Subject: [PYTHON MATRIX-SIG] First experiences
In-Reply-To: <9601301950.AA04262@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601302043.PAA29453@cyclone.ERE.UMontreal.CA>


   Actually, reshape is now an array method, and the old reshape function
   is only around for "historical reasons".  I should probably remove it.

One or the other. I am not sure that "everything as a method" is the
right strategy. For example, operations that have two symmetric
operands look a bit odd as methods. There's also a difference in
behaviour, since array functions accept nested lists instead of
arrays, but methods can be called only on previously existing array
objects. In the case of the "copying reshape", the array argument
would often be a constant and it would make perfect sense to allow
nested lists there.

A useful way to make use of the function/method distinction would be
to use methods for operations that modify an array and functions for
operations that don't. The modified array would then be the one on
which the method is called, and it makes sense to require that this
actually is an array. There are not too many in-place operations right
now, but there will be once topics like linear algebra are dealt
with. For example, it would be nice to have
  m.invert()
for an in-place inversion and
  inverse(m)
for a function that returns the inverse without changing m.

   This can easily be added to the standard set of functions and
   implemented on top of the existing transpose and concat methods.  You
   might want to do this as an exercise ;).  

No problem, but that would certainly be slow!

   I was actually asking for a new name for the method that will do a
   reshape allowing you to make copies of the array in the process.  I'm

I see. Now that's difficult. I have been calling this operation
"reshape" since my high school days, so it is not easy to come
up with something else! Give me some time...

-------------------------------------------------------------------------------
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  Tue Jan 30 17:26:11 1996
From: hinsenk@ere.umontreal.ca (Hinsen Konrad)
Date: Tue, 30 Jan 1996 12:26:11 -0500
Subject: [PYTHON MATRIX-SIG] First experiences
In-Reply-To: <9601301635.AA03443@baribal.LCS.MIT.EDU.LCS.MIT.EDU> (jjh@Goldilocks.LCS.MIT.EDU)
Message-ID: <199601301726.MAA16169@cyclone.ERE.UMontreal.CA>


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

In the spirit of "no needless redundancies", it would be better not to
have this function. Maybe we should add an (optional) module with
standard abbreviations, where we would simply write sum =
add.reduce. That would also be a good way to have clearer standard
names for things like arange() while still having short alternatives
that are available on every system.

   And vice versa.  This is mainly a matter of personal taste, and since
   my taste favors fast_umath, that's going to be the default version for

Its not personal taste, but consistency. I have replaced "fast_umath"
by "umath" in my installation, but then immediately added "from
fast_umath import *" to my only application. I expect to use
mostly the fast version for debugged code, but still I think that
the default should obey the principle of least surprise, and that
is maximum similarity to Python scalar behaviour.

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

It could still return a new pointer if the size is the same,
and make a copy only if the size changes. Personally I don't care
about dimension checking; in all my APL code that has never been
a problem. If the size remains the same, then typically the
new dimensions are specified as an expression involving the old
dimensions. I have never had an error there.

   Try this:

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

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

Not really. First of all, in most cases I need a non-destructive
version, similar to sequence addition. Second, I really need
it for all dimensions. In my application, I have two 1d arrays
of equal length and have to construct a 2d array from them.
What I used is
   c = array([tuple(a), tuple(b)])
but there ought to be a much cleaner and more efficient way.

BTW, we also ought to have a way to convert arrays to nested
lists and maybe tuples. Oddly enough, Python has no built-in
function list(), although it does have tuple().

   It should probably work along any axis, but I don't have a terribly
   good way to specify the axis and still keep the nice feature of being
   able to concat together an arbitrary number of arrays (very important

One argument could be a tuple of all arrays to be concatenated.

   for efficiency).  It would also be a bit of a hassle to write in C the
   way you're suggesting, would it be enough to add in a standard python
   function with the desired behavior?

That's just a matter of efficiency and has to be tried. In my APL code
this function is used a lot, and often on small arrays.

-------------------------------------------------------------------------------
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  Tue Jan 30 22:53:56 1996
From: chris.chase@jhuapl.edu (Chris Chase S1A)
Date: Tue, 30 Jan 1996 17:53:56 -0500
Subject: [PYTHON MATRIX-SIG] Pseudo Indices
In-Reply-To: <199601301809.NAA08602@monty>
References: <9601301742.AA03714@baribal.LCS.MIT.EDU.LCS.MIT.EDU>
 <199601301809.NAA08602@monty>
Message-ID: <199601302248.RAA28764@python.org>


>> a[RubberIndex, 3].

Guido> You could sneak this into the abovementioned patch as "a[::, 3]".

Actually, All is equivalent to "::" and it corresponds to the nil
index syntax of Yorick (which is indicated by whitespace between the
commas) and the * index syntax of Matlab or IDL.

Rubber indexes are different.  Yorick has two types of rubber indexes,
one has syntax "*" and the other is ".." and neither type has the same
behavior as "::".  Both types act as if the entire length of the
missing intervening dimensions were selected.  "*" collapses the
missing intervening dimensions into 1 dimension.  ".." does not
collapse the intervening dimensions (it is like using All for the
missing dimensions).

Currently the Numeric module RubberIndex is like the Yorick ".."
rubber index.  I imagine that the collapsing type rubber index could
easily be added by applying a shape change to the current RubberIndex
behavior.  What would be a possible name for this type of rubber
index?  CollapseIndex?

Chris


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

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

From jjh@Goldilocks.LCS.MIT.EDU  Wed Jan 31 15:56:04 1996
From: jjh@Goldilocks.LCS.MIT.EDU (James Hugunin)
Date: Wed, 31 Jan 96 10:56:04 EST
Subject: [PYTHON MATRIX-SIG] Slices as :
In-Reply-To: <199601302248.RAA28764@python.org> (message from Chris Chase S1A on Tue, 30 Jan 1996 17:53:56 -0500)
Message-ID: <9601311556.AA19776@baribal.LCS.MIT.EDU.LCS.MIT.EDU>


The following is mainly directed to Chris, but I thought that people
on the list might be interested, so I decided to include the CC.


Well, it looks like your slices patch is going to get itself added to
python after all.  Guido turned out to be a softer touch than I'd
expected.  If you'd been at the workshop when I started talking about
rubber indices, you'd better understand my fears.

I'd like to see a couple of changes to your slices patch to make my
life easier for adding it into the NumericPython distribution.

Could you prepare a version of your patches that include both 

1::2 -> slice(1,None,2) 
and
::: or .. (you pick, but it might get changed by popular vote)
	-> Py_Ellipses (a special object just like Py_None)

I'd also prefer to see 1:2:3:4 -> Syntax Error rather than a runtime
error.

I know that a[:] is unchanged by your patches for backwards
compatibilty.  It would be nice if a[::-1] would be turned into
a[slice(None,None,-1) so that it could be passed to the mapping
protocol rather than being a syntax error.

I don't think that pseudo indices should have special notation as
these are particular to the array object.  Konrad's name of
Numeric.NewAxis strikes me as a good idea.

I also don't think that it is necessary to add special notation for
the compressing rubber index as this is done easily enough with
reshape when needed.

Does this all sound reasonable to you?

Could you prepare this as a patch on top of the 0.32 distribution (on
top of Konrad's existing patches)?  

As soon as you get this patch to me I'll add it into my working
version and to the next distribution.

I understand other commitments, but the sooner you could get this to
me the better.

Thanks for your help - Jim


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

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