[Numpy-discussion] subclassing matrix
Colin J. Williams
cjw@sympatico...
Thu Jan 10 09:03:43 CST 2008
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
More information about the Numpy-discussion
mailing list