File: __init__.py

package info (click to toggle)
python-numarray 1.5.2-4
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 8,668 kB
  • ctags: 11,384
  • sloc: ansic: 113,864; python: 22,422; makefile: 197; sh: 11
file content (251 lines) | stat: -rw-r--r-- 6,730 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
""" numarray.matrix ports/re-implements the Matrix module from Numeric.

The basic goal of numarray.matrix is to provide a quick and dirty matrix
class which is backward compatible with Numeric's Matrix class.

In numarray, Matrix() is a factory function for _Matrix, which is a
subclass of NumArray.  _Matrix is not yet itself subclassable.
Because a _Matrix is a subclass of NumArray, it can be used where a
NumArray can be used without conversion, particularly in C.

A _Matrix can be constructed from a 2D nested sequence:

>>> m = Matrix( [[1,2,3],[11,12,13],[21,22,23]]); m
_Matrix([[ 1,  2,  3],
       [11, 12, 13],
       [21, 22, 23]])

Or,  a _Matrix can be constructed from an abbreviated string description:

>>> m = Matrix("1 2 3; 6 5 4; 9 20 2"); m
_Matrix([[ 1,  2,  3],
       [ 6,  5,  4],
       [ 9, 20,  2]])

Because a _Matrix is a subclass of numarray,  most NumArray methods and
behavior are identical.  In particular,  a _Matrix can be indexed as a 2D
array:

>>> m[1:2,1:2]
_Matrix([[5]])

_Matrix overloads the * operator to perform matrix multiplication rather
than elementwise multiplication:
       
>>> m*m
_Matrix([[ 40,  72,  17],
       [ 72, 117,  46],
       [147, 158, 111]])

_Matrix defines an "array" attribute to return the contents of the matrix
as a 2D NumArray.  Here,  NumArray multiplication is shown to be elementwise
multiplication:

>>> m.array*m.array
array([[  1,   4,   9],
       [ 36,  25,  16],
       [ 81, 400,   4]])

Checking if the determinant is close to zero can determine if a matrix
is singular or not.

>>> EPS = 1e-13            # fudge an epsilon... your mileage may vary
>>> m.determinant() < EPS  # singular?
0

_Matrix overloads the __pow__ special method to perform matrix
multiplication and inversion.  Since m is non-singular, we can invert
it.  _Matrix inversion is represented using **-1 notation:

>>> m**-1                  
_Matrix([[-0.34482759,  0.27586207, -0.03448276],
       [ 0.1182266 , -0.12315271,  0.06896552],
       [ 0.36945813, -0.00985222, -0.03448276]])

Of course multiplying by the inverse should give something close to identity.

>>> numarray.allclose(m*m**-1, numarray.identity(3), atol=EPS)
1

You can use numarray's transpose() function to compute the transpose of
a _Matrix:

>>> transpose(m)
_Matrix([[ 1,  6,  9],
       [ 2,  5, 20],
       [ 3,  4,  2]])

Raising a matrix to a positive power results in matrix multiplication
by itself as illustrated in the _fibonacci function:

>>> _fibonacci(10)
Fibonacci numbers: 1 1 2 3 5 8 13 21 34 55

"""

import string
import types

import numarray
from numarray import asarray, dot as _dot, identity, conjugate, NumArray, shape
from numarray import transpose as transpose
import numarray.linear_algebra as LinearAlgebra

def _fibonacci(n=10):
    """A self test demo function from Numeric's Matrix."""
    print "Fibonacci numbers:",
    m = Matrix([[1,1],[1,0]])
    for i in range(n):
        mm=m**i
        print mm[0][0],
    print

# make translation table
_table = [None]*256
for k in range(256):
    _table[k] = chr(k)
_table = ''.join(_table)

_numchars = string.digits + ".-+jeEL"
_todelete = []
for k in _table:
    if k not in _numchars:
        _todelete.append(k)
_todelete = ''.join(_todelete)

def _eval(astr):
    return eval(astr.translate(_table,_todelete))

def _convert_from_string(data):
    data.find
    rows = data.split(';')
    newdata = []
    count = 0
    for row in rows:
        trow = row.split(',')
        newrow = []
        for col in trow:
            temp = col.split()
            newrow.extend(map(_eval,temp))
        if count == 0:
            Ncols = len(newrow)
        elif len(newrow) != Ncols:
            raise ValueError, "Rows not the same size."
        count += 1
        newdata.append(newrow)
    return newdata


_lkup = {'0':'000',
         '1':'001',
         '2':'010',
         '3':'011',
         '4':'100',
         '5':'101',
         '6':'110',
         '7':'111'}

def _binary(num):
    ostr = oct(num)
    bin = ''
    for ch in ostr[1:]:
        bin += _lkup[ch]
    ind = 0
    while bin[ind] == '0':
        ind += 1
    return bin[ind:]

class _Matrix(NumArray):
    def _rc(self, a):
        if len(shape(a)) == 0:
            return a
        else:
            return Matrix(a)
            
    def __mul__(self, other):
        aother = asarray(other)
        if len(aother.shape) == 0:
            return self._rc(self*aother)
        else:
            return self._rc(_dot(self, aother))

    def __rmul__(self, other):
        aother = asarray(other)
        if len(aother.shape) == 0:
            return self._rc(aother*self)
        else:
            return self._rc(_dot(aother, self))

    def __imul__(self,other):
        aother = asarray(other)
        self[:] = _dot(self, aother)
        return self

    def __pow__(self, other):
        shape = self.shape
        if len(shape)!=2 or shape[0]!=shape[1]:
            raise TypeError, "matrix is not square"
        if type(other) not in (type(1), type(1L)):
            raise TypeError, "exponent must be an integer"        
        if other==0:
            return Matrix(identity(shape[0]))
        if other<0:
            result=Matrix(LinearAlgebra.inverse(self))
            x=Matrix(result)
            other=-other
        else:
            result=self
            x=result
        if other <= 3:
            while(other>1):
                result=result*x
                other=other-1
            return result
        # binary decomposition to reduce the number of Matrix
        #  Multiplies for other > 3.
        beta = _binary(other)            
        t = len(beta)
        Z,q = x.copy(),0
        while beta[t-q-1] == '0':
            Z *= Z
            q += 1
        result = Z.copy()
        for k in range(q+1,t):
            Z *= Z
            if beta[t-k-1] == '1':
                result *= Z
        return result

    def __rpow__(self, other):
        raise TypeError, "x**y not implemented for matrices y"

    def __invert__(self):
        return Matrix(conjugate(self))

    def determinant(self):
        """Computes the determinant of the matrix."""
        return LinearAlgebra.determinant(self)

    def getarray(self):
        v = self.view()
        v.__class__ = NumArray
        return v

    array = property(getarray, None, "NumArray form of a Matrix")


def Matrix(data, typecode=None, copy=1, savespace=0):
    if type(data) is types.StringType:
        data = _convert_from_string(data)
    a = numarray.fromlist(data, type=typecode)
    a.__class__ = _Matrix
    return a


def test():
    import doctest, __init__
    return doctest.testmod(__init__)

if __name__ == '__main__':
    print test()