Re: [Numpy-discussion] subclassing matrix

2008-01-12 Thread Basilisk96
On Jan 12, 1:36 am, Timothy Hochberg [EMAIL PROTECTED] wrote:
 I believe that you need to look at __array_finalize__ and __array_priority__
 (and there may be one other thing as well, I can't remember; it's late).
 Search for __array_finalize__ and that will probably help get you started.


Well sonovagun!
I removed the hack.
Then just by setting __array_priority__ = 20.0 in the class body,
things are magically working almost as I expect. I say almost
because of this custom method:

def cross(self, other):
Cross product of this vector and another vector
return _N.cross(self, other, axis=0)

That call to numpy.cross returns a numpy.ndarray. Unless I do return
Vector(_N.cross(self, other, axis=0)), I get problems downstream.

When is __array_finalize__ called? By adding some print traces, I can
see it's called every time an array is modified in any way i.e.,
reshaped, transposed, etc., and also during operations like u+v, u-v,
A*u. But it's not called during the call to numpy.cross. Why?

Cheers,
-Basilisk96
___
Numpy-discussion mailing list
Numpy-discussion@scipy.org
http://projects.scipy.org/mailman/listinfo/numpy-discussion


Re: [Numpy-discussion] subclassing matrix

2008-01-12 Thread Colin J. Williams
Basilisk96 wrote:
 On Jan 12, 1:36 am, Timothy Hochberg [EMAIL PROTECTED] wrote:
 I believe that you need to look at __array_finalize__ and __array_priority__
 (and there may be one other thing as well, I can't remember; it's late).
 Search for __array_finalize__ and that will probably help get you started.

 
 Well sonovagun!
 I removed the hack.
 Then just by setting __array_priority__ = 20.0 in the class body,
 things are magically working almost as I expect. I say almost
 because of this custom method:
 
 def cross(self, other):
 Cross product of this vector and another vector
 return _N.cross(self, other, axis=0)
 
 That call to numpy.cross returns a numpy.ndarray. Unless I do return
 Vector(_N.cross(self, other, axis=0)), I get problems downstream.
 
 When is __array_finalize__ called? By adding some print traces, I can
 see it's called every time an array is modified in any way i.e.,
 reshaped, transposed, etc., and also during operations like u+v, u-v,
 A*u. But it's not called during the call to numpy.cross. Why?
 
 Cheers,
 -Basilisk96

This may help.  It is based on your 
initial script.

The Vectors are considered as columns 
but presented as rows.

This adds a complication which is not 
resolved.

Colin W.

#-- vector.py
import numpy as _N
import math as _M
#default tolerance for equality tests
TOL_EQ = 1e-6
#default format for pretty-printing 
Vector instances
FMT_VECTOR_DEFAULT = %+.5f

class Vector(_N.matrix):
 
 2D/3D vector class that supports 
numpy matrix operations and more.

 Examples:
 u = Vector([1,2,3])
 v = Vector('3 4 5')
 w = Vector([1, 2])
 
 def __new__(cls, data=0. 0. 0., 
dtype=_N.float64):
 
 Subclass instance constructor.

 If data is not specified, a 
zero Vector is constructed.
 The constructor always 
returns a Vector instance.
 The instance gets a 
customizable Format attribute, which
 controls the printing 
precision.
 
 data= [1, 2, 3]
 ret= _N.matrix(data, dtype)
##ret = super(Vector, 
cls).__new__(cls, data, dtype=dtype)

###promote the instance to cls type.
##ret.__class__ = cls
 assert ret.size in (2, 3), 
'Vector must have either two or three 
components'
 if ret.shape[0] == 1:
 ret = ret.T
 assert ret.shape == 
(ret.shape[0], 1), 'could not express 
Vector as a Mx1 matrix'
 if ret.shape[0] == 2:
 ret = _N.vstack((ret, 0.))
 ret.Format = FMT_VECTOR_DEFAULT
 ret=  _N.ndarray.__new__(cls, 
ret.shape, dtype,
 
buffer=ret.data)
 return ret

 def __str__(self):
 fmt = getattr(self, Format, 
FMT_VECTOR_DEFAULT)
 fmt = ', '.join([fmt]*3)
 return ''.join([(, fmt, )]) 
% tuple(self.T.tolist()[0])

 def __repr__(self):
 fmt = ', '.join(['%s']*3)
 return ''.join([%s([, fmt, 
])]) % tuple([self.__class__.__name__] 
+ self.T.tolist()[0])

 def __mul__(self, mult):
   ''' self * multiplicand '''
   if isinstance(mult, _N.matrix):
 return _N.dot(self, mult)
   else:
 raise DataError, 'multiplicand 
must be a Vector or a matrix'

 def __rmul__(self, mult):
   ''' multiplier * self.__mul__ '''
   if isinstance(mult, _N.matrix):
 return Vector(_N.dot(mult, self))
   else:
 raise DataError, 'multiplier 
must be a Vector or a matrix'

  the remaining methods are 
Vector-specific math operations, 
including the X,Y,Z properties...
if __name__ == '__main__':
   u = Vector('1 2 3')
   print str(u)
   print repr(u)
   A = _N.matrix('2 0 0; 0 2 0; 0 0 2')
   print A
   p = A * u
   print p
   print  p.__class__
   q= u.T * A
   try:
 print q
   except:
 print we don't allow for the 
display of row vectors
   print q.A, q.T
   print q.__class__
___
Numpy-discussion mailing list
Numpy-discussion@scipy.org
http://projects.scipy.org/mailman/listinfo/numpy-discussion


Re: [Numpy-discussion] subclassing matrix

2008-01-12 Thread Basilisk96
Thanks Stefan and Colin,

The subclass documentation made this a little clearer now. Instead of
using a super() call in __new__, I now do this:

#construct a matrix based on the input
ret = _N.matrix(data, dtype=dtype)
#promote it to Vector
ret = ret.view(cls)

The second statement there also invokes a call to __array_finalize__,
which ensures that the Format attribute is attached to the instance.
Then I validate and manipulate the shape of the matrix so that it is a
(3,1) vector. Now the instance builder is proper.

my __array_finalize__ looks like this:

def __array_finalize__(self, obj):
self.Format = getattr(obj, Format, FMT_VECTOR_DEFAULT)
return

Also, after learning about the view method, I am now doing the
following in Vector.cross:

def cross(self, other):
Cross product of this vector and another vector
#calling the result's view method promotes it to Vector
result = _N.cross(self, other, axis=0)
result = result.view(type(self))
return result

It also works if I just use Vector(...), but it is my gut feeling that
invoking a view vs. instantiating a new Vector instance is cheaper?

Now I can add more unit tests.

Cheers,
-Basilisk96
___
Numpy-discussion mailing list
Numpy-discussion@scipy.org
http://projects.scipy.org/mailman/listinfo/numpy-discussion


Re: [Numpy-discussion] subclassing matrix

2008-01-11 Thread Basilisk96
On Jan 11, 2008, Colin J. Williams wrote:

 You make a good case that it's good not
 to need to ponder what sort of
 vector you are dealing with.

 My guess is that the answer to your
 question is no but I would need to
 play with your code to see that.  My
 feeling is that, at the bottom of
 the __new__ module, the returned object
 should be an instance of the
 Vector class.

 It's been a while since I've worked with
 numpy and so I'll look at it
 and hope that someone gives you a
 definitive answer before I sort it out.

 Colin W.

Well, let's say that I get rid of that class promotion line. When the
input object to the constructor is a string or a tuple
such as Vector('1 2 3') or Vector([1,2,3]), then the returned object
is always an instance of Vector. However, when the input object is a
numpy.matrix instance, the returned object remains a numpy.matrix
instance! So by doing that little hack, I promote it to Vector.

BUT...

It seems that I have solved only half of my problem here. The other
half rears its ugly head when I perform operations between instances
of numpy.matrix and Vector. The result ends up returning a matrix,
which is bad because it has no knowledge of any custom Vector
attributes. Here's a simple case:

  u = Vector('1 2 3')  #Vector instance
  P = numpy.mat(numpy.eye(3))   #matrix instance
  u_new = P*u   #matrix instance, not desirable!
  u_new_as_Vector = Vector(P*u)  #Vector instance

I'd rather not have to remember to re-instantiate the result in client
code. I think I understand why this is happening - the code in
numpy.core.defmatrix.matrix.__mul__ goes like this:

def __mul__(self, other):
if isinstance(other,(N.ndarray, list, tuple)) :
# This promotes 1-D vectors to row vectors
return N.dot(self, asmatrix(other))
if N.isscalar(other) or not hasattr(other, '__rmul__') :
return N.dot(self, other)
return NotImplemented

It passes the first condition: isinstance(other,(N.ndarray)) is true;
and so the return value becomes a matrix.

Bummer.
Do I also need to override a few overloaded methods like __mul__,
__rmul__, etc. to make this work?

Cheers,
-Basilisk96
___
Numpy-discussion mailing list
Numpy-discussion@scipy.org
http://projects.scipy.org/mailman/listinfo/numpy-discussion


Re: [Numpy-discussion] subclassing matrix

2008-01-11 Thread Timothy Hochberg
On Jan 11, 2008 9:59 PM, Basilisk96 [EMAIL PROTECTED] wrote:

 On Jan 11, 2008, Colin J. Williams wrote:

  You make a good case that it's good not
  to need to ponder what sort of
  vector you are dealing with.
 
  My guess is that the answer to your
  question is no but I would need to
  play with your code to see that.  My
  feeling is that, at the bottom of
  the __new__ module, the returned object
  should be an instance of the
  Vector class.
 
  It's been a while since I've worked with
  numpy and so I'll look at it
  and hope that someone gives you a
  definitive answer before I sort it out.
 
  Colin W.

 Well, let's say that I get rid of that class promotion line. When the
 input object to the constructor is a string or a tuple
 such as Vector('1 2 3') or Vector([1,2,3]), then the returned object
 is always an instance of Vector. However, when the input object is a
 numpy.matrix instance, the returned object remains a numpy.matrix
 instance! So by doing that little hack, I promote it to Vector.

 BUT...

 It seems that I have solved only half of my problem here. The other
 half rears its ugly head when I perform operations between instances
 of numpy.matrix and Vector. The result ends up returning a matrix,
 which is bad because it has no knowledge of any custom Vector
 attributes. Here's a simple case:

  u = Vector('1 2 3')  #Vector instance
  P = numpy.mat(numpy.eye(3))   #matrix instance
  u_new = P*u   #matrix instance, not desirable!
  u_new_as_Vector = Vector(P*u)  #Vector instance

 I'd rather not have to remember to re-instantiate the result in client
 code. I think I understand why this is happening - the code in
 numpy.core.defmatrix.matrix.__mul__ goes like this:

def __mul__(self, other):
if isinstance(other,(N.ndarray, list, tuple)) :
# This promotes 1-D vectors to row vectors
return N.dot(self, asmatrix(other))
if N.isscalar(other) or not hasattr(other, '__rmul__') :
return N.dot(self, other)
return NotImplemented

 It passes the first condition: isinstance(other,(N.ndarray)) is true;
 and so the return value becomes a matrix.

 Bummer.
 Do I also need to override a few overloaded methods like __mul__,
 __rmul__, etc. to make this work?



I believe that you need to look at __array_finalize__ and __array_priority__
(and there may be one other thing as well, I can't remember; it's late).
Search for __array_finalize__ and that will probably help get you started.



-- 
.  __
.   |-\
.
.  [EMAIL PROTECTED]
___
Numpy-discussion mailing list
Numpy-discussion@scipy.org
http://projects.scipy.org/mailman/listinfo/numpy-discussion


Re: [Numpy-discussion] subclassing matrix

2008-01-10 Thread Colin J. Williams
Basilisk96 wrote:
 Hello folks,
 
 In the course of a project that involved heavy use of geometry and
 linear algebra, I found it useful to create a Vector subclass of
 numpy.matrix (represented as a column vector in my case).

Why not consider a matrix with a shape 
of (1, n) as a row vector and
one with (n, 1) as a column vector?

Then you can simply write A * u or u.T * A.

Does this not meet the need?

You could add methods isRowVector and 
isColumnVector to the Matrix class.

Colin W.
 
 I'd like to hear comments about my use of this class promotion
 statement in __new__:
 ret.__class__ = cls
 
 It seems to me that it is hackish to just change an instance's class
 on the fly, so perhaps someone could clue me in on a better practice.
 Here is my reason for doing this:
 Many applications of this code involve operations between instances of
 numpy.matrix and instances of Vector, such as applying a linear-
 operator matrix on a vector. If I omit that class promotion
 statement, then the results of such operations cannot be instantiated
 as Vector types:
  from vector import Vector
  import numpy
  u = Vector('1 2 3')
  A = numpy.matrix('2 0 0; 0 2 0; 0 0 2')
  p = Vector(A * u)
  p.__class__
 class 'numpy.core.defmatrix.matrix'
 
 This is undesirable because the calculation result loses the custom
 Vector methods and attributes that I want to use. However, if I use
 that class promotion statement, the p.__class__ lookup returns what
 I want:
  p.__class__
 class 'vector.Vector'
 
 Is there a better way to achieve that?
 
 Here is the partial subclass code:
 #-- vector.py
 import numpy as _N
 import math as _M
 #default tolerance for equality tests
 TOL_EQ = 1e-6
 #default format for pretty-printing Vector instances
 FMT_VECTOR_DEFAULT = %+.5f
 
 class Vector(_N.matrix):
 
 2D/3D vector class that supports numpy matrix operations and more.
 
 Examples:
 u = Vector([1,2,3])
 v = Vector('3 4 5')
 w = Vector([1, 2])
 
 def __new__(cls, data=0. 0. 0., dtype=_N.float64):
 
 Subclass instance constructor.
 
 If data is not specified, a zero Vector is constructed.
 The constructor always returns a Vector instance.
 The instance gets a customizable Format attribute, which
 controls the printing precision.
 
 ret = super(Vector, cls).__new__(cls, data, dtype=dtype)
 #promote the instance to cls type.
 ret.__class__ = cls
 assert ret.size in (2, 3), 'Vector must have either two or
 three components'
 if ret.shape[0] == 1:
 ret = ret.T
 assert ret.shape == (ret.shape[0], 1), 'could not express
 Vector as a Mx1 matrix'
 if ret.shape[0] == 2:
 ret = _N.vstack((ret, 0.))
 ret.Format = FMT_VECTOR_DEFAULT
 return ret
 
 def __str__(self):
 fmt = getattr(self, Format, FMT_VECTOR_DEFAULT)
 fmt = ', '.join([fmt]*3)
 return ''.join([(, fmt, )]) % (self.X, self.Y, self.Z)
 
 def __repr__(self):
 fmt = ', '.join(['%s']*3)
 return ''.join([%s([, fmt, ])]) %
 (self.__class__.__name__, self.X, self.Y, self.Z)
 
  the remaining methods are Vector-specific math operations,
 including the X,Y,Z properties...
 
 
 Cheers,
 -Basilisk96

___
Numpy-discussion mailing list
Numpy-discussion@scipy.org
http://projects.scipy.org/mailman/listinfo/numpy-discussion


Re: [Numpy-discussion] subclassing matrix

2008-01-10 Thread Basilisk96
Yes, that certainly meets the need.

In previous applications, I never thought to use Vector because it was
sufficient for me to adopt the convention of a column vector to
represent XY points.  That way, I could do things like c * R * u + t.
Isn't that simple? Not only is it easy on the eyes, but it follows
most academic definitions that I know. Furthermore, I was able to
apply linear operators to a whole set of XY points by doing something
to the tune of:
u = numpy.hstack(tuple_of_points_from_ascii_file)# u.shape is
(2, n)
R = some_2d_numpy_rotation_matrix# R.shape is (2, 2)
t = numpy.mat(1.; 3.)
v = R * u + t   # v.shape is the same as u.shape

So, the need arose for a self-contained Vector class that inherently
supports a number of common geometric operations, and uses numpy for
them. It seemed natural to subclass matrix because numpy.array is a
general-case array; numpy.matrix restricts that to an array of rank 2;
and Vector further restricts that to a *column* array of rank 2.

Now, if I were to write a custom library of my common vector
operations using module functions, I'd have to always keep in mind
that they must operate on either column or row vectors, but not both.
Instead, I chose to write a subclass of a well-tested class and
explicitly forced all Vector instances to be columns.

Vector has a number of methods that wrap numpy functions within the
Vector context. For example:
def cross(self, other):
Cross product of this vector and another vector
if isinstance(other, self.__class__):
return Vector(_N.cross(self, other, axis=0))
else:
raise TypeError('Both arguments must be of type Vector')

I think that a call like w = u.cross(v) is less verbose than having to
remember the `axis` argument in numpy.cross(u, v, axis=0). Yes, I
realize that it would not be required if the vectors were row
matrices, but then I'd have to live with using u.T * A, which I don't
particularly like either.

But now I can do things like:

from vector import Vector
u = Vector('1 2 3')
v = Vector('3 2 1')
w = u.cross(v)
print w
   (-4.0, +8.0, -4.0)
alpha = u.angle(w)
print alpha
   1.57079632679
..and so on.

However, my original question still stands: is
ret.__class__ = cls
a good idea?

Cheers,
-Basilisk96


On Jan 10, 10:03 am, Colin J. Williams [EMAIL PROTECTED] wrote:
 Basilisk96 wrote:
  Hello folks,

  In the course of a project that involved heavy use of geometry and
  linear algebra, I found it useful to create a Vector subclass of
  numpy.matrix (represented as a column vector in my case).

 Why not consider a matrix with a shape
 of (1, n) as a row vector and
 one with (n, 1) as a column vector?

 Then you can simply write A * u or u.T * A.

 Does this not meet the need?

 You could add methods isRowVector and
 isColumnVector to the Matrix class.

 Colin W.





  I'd like to hear comments about my use of this class promotion
  statement in __new__:
  ret.__class__ = cls

  It seems to me that it is hackish to just change an instance's class
  on the fly, so perhaps someone could clue me in on a better practice.
  Here is my reason for doing this:
  Many applications of this code involve operations between instances of
  numpy.matrix and instances of Vector, such as applying a linear-
  operator matrix on a vector. If I omit that class promotion
  statement, then the results of such operations cannot be instantiated
  as Vector types:
   from vector import Vector
   import numpy
   u = Vector('1 2 3')
   A = numpy.matrix('2 0 0; 0 2 0; 0 0 2')
   p = Vector(A * u)
   p.__class__
  class 'numpy.core.defmatrix.matrix'

  This is undesirable because the calculation result loses the custom
  Vector methods and attributes that I want to use. However, if I use
  that class promotion statement, the p.__class__ lookup returns what
  I want:
   p.__class__
  class 'vector.Vector'

  Is there a better way to achieve that?

  Here is the partial subclass code:
  #-- vector.py
  import numpy as _N
  import math as _M
  #default tolerance for equality tests
  TOL_EQ = 1e-6
  #default format for pretty-printing Vector instances
  FMT_VECTOR_DEFAULT = %+.5f

  class Vector(_N.matrix):
  
  2D/3D vector class that supports numpy matrix operations and more.

  Examples:
  u = Vector([1,2,3])
  v = Vector('3 4 5')
  w = Vector([1, 2])
  
  def __new__(cls, data=0. 0. 0., dtype=_N.float64):
  
  Subclass instance constructor.

  If data is not specified, a zero Vector is constructed.
  The constructor always returns a Vector instance.
  The instance gets a customizable Format attribute, which
  controls the printing precision.
  
  ret = super(Vector, cls).__new__(cls, data, dtype=dtype)
  #promote the instance to cls type.