00001 """
00002 Augmented Utilites Toolbox
00003 """
00004
00005 __copyright__ = """
00006 Copyright 2008 Sean Ross-Ross
00007 """
00008 __license__ = """
00009 This file is part of SLIMpy .
00010
00011 SLIMpy is free software: you can redistribute it and/or modify
00012 it under the terms of the GNU Lesser General Public License as published by
00013 the Free Software Foundation, either version 3 of the License, or
00014 (at your option) any later version.
00015
00016 SLIMpy is distributed in the hope that it will be useful,
00017 but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00019 GNU Lesser General Public License for more details.
00020
00021 You should have received a copy of the GNU Lesser General Public License
00022 along with SLIMpy . If not, see <http://www.gnu.org/licenses/>.
00023 """
00024
00025
00026 from slimpy_base.Core.User.Structures.serial_vector import Vector
00027 from slimpy_base.Core.User.linop.linear_operator import LinearOperator, CompoundOperator
00028 import numpy
00029 from numpy import ndarray,array
00030
00031 class AugMatrix( object ):
00032 """
00033 base class for AugmentVector and AugmentOperator
00034 """
00035 def __init__( self, mat ):
00036 self.matrix = numpy.matrix( mat )
00037
00038
00039 def getattrs( self, name ):
00040 A = self.matrix.A
00041 B = numpy.zeros_like( A )
00042
00043 for i in range( len( A ) ):
00044 for j in range( len( A[i] ) ):
00045 if hasattr( A[i][j], name ):
00046 B[i][j] = getattr( A[i][j], name )
00047
00048 return B
00049
00050 def callattrs( self, name, *args, **kargs ):
00051
00052 A = self.getattrs( name )
00053
00054 for i in range( len( A ) ):
00055 for j in range( len( A[i] ) ):
00056 if callable( A[i][j] ):
00057 A[i][j] = A[i][j]( *args, **kargs )
00058
00059 return A
00060
00061 def __array__(self):
00062 return self.matrix.A
00063
00064 class aug_oper( LinearOperator, AugMatrix ):
00065 """
00066 Augmented operator class used to combine many operators into a
00067 matrix of operators
00068 """
00069 def __init__( self, mat ):
00070
00071 AugMatrix.__init__( self, mat )
00072
00073 LinearOperator.__init__( self, self.domain(), self.range() )
00074
00075
00076 def __str__( self ):
00077 """
00078 Returns the operators name and attributes
00079 """
00080 msg = "Augmented Linear Operator:"
00081
00082 spc = '\n'+" "*len( msg )
00083 mat = str( self.matrix )
00084 return msg + spc.join( mat.splitlines() )
00085
00086 def getName( self ):
00087
00088 return self.name + ( ( self.isadj and "Adj" ) or '' )
00089
00090 def __repr__( self ):
00091 """
00092 Returns the operators name from operator_dict
00093 """
00094 return "aug_oper: "+self.matrix.__repr__()
00095
00096 def domain( self ):
00097 return self.callattrs( "domain" )
00098
00099 def range( self ):
00100 return self.callattrs( "range" )
00101
00102 def copy( self ):
00103 """
00104 Perform shallow copy of self
00105 """
00106 return aug_oper( self.matrix )
00107
00108 def adj( self ):
00109 """
00110 Returns the adjoint of all the enclosed operators
00111 and the transpose of this one
00112 """
00113 T = self.callattrs( "adj" )
00114 return aug_oper(T)
00115
00116 def applyop( self, other ):
00117 """
00118 apply this operator to an augmented vector
00119 """
00120 if isinstance( other, aug_vec ):
00121 return aug_vec( self.matrix * other.matrix )
00122
00123 if isinstance( other, aug_oper ):
00124 raise NotImplementedError
00125 else:
00126 raise TypeError( "this operator can only be called on a vector or another operator" )
00127
00128
00129 def getdim( self ):
00130 """
00131 Returns the dimensions of the operator. Usually not defined.
00132 """
00133 raise NotImplementedError
00134
00135
00136
00137 def norm( self ):
00138 """
00139 reutrns an AugOper that contains the norms of these operators
00140 """
00141 return aug_oper( self.callattrs( 'norm' ) )
00142
00143 def normalize( self ):
00144 """
00145 reutrns an AugOper that containing Compound operators
00146 """
00147 A = self.matrix.A
00148 B = self.norm().matrix.A
00149 C = numpy.empty_like( A )
00150
00151
00152 for i in range( len( A ) ):
00153 for j in range( len( A[i] ) ):
00154 C[i][j] = CompoundOperator( [B[i][j], A[i][j]] )
00155
00156 return aug_oper( C )
00157
00158 def minvelconst( self, *args, **kargs ):
00159 """
00160 TODO: take minvelconst out of linear operator
00161 """
00162 return numpy.mat( self.callattrs( 'minvelconst', *args, **kargs ) )
00163
00164
00165 class aug_vec( Vector, AugMatrix ):
00166 """
00167 Augmented vector class used to combine many operators into a
00168 matrix of operators
00169 """
00170 def __init__( self, mat ):
00171
00172 AugMatrix.__init__( self, mat )
00173
00174 def __str__( self ):
00175 return "augmented vector:\n" + str( self.matrix )
00176
00177 def __repr__( self ):
00178 return "aug_vec:\n" + str( self.matrix )
00179
00180 def __getitem__( self, index ):
00181 """
00182 If index is a string: Returns an item from one of the dictionaries. Checks the vector dictionary first.
00183 If index is a number: Returns a number at index from the binary file.
00184 """
00185 return self.matrix.__getitem__( (index, 0) )
00186
00187 def __setitem__( self, index, item ):
00188 """
00189 Sets an item in the vector dictionary
00190 """
00191 self.matrix.__setitem__( (index, 0), item )
00192 return
00193
00194
00195
00196 def getSpace( self ):
00197 """
00198 returns a Space object that contains all of the information
00199 about this vector
00200 """
00201 return self.callattrs( "getSpace" )
00202
00203
00204 def __getslice__( self, start, stop, step=1 ):
00205 """
00206 Returns a numarray array from index i to j from the binary file.
00207 If j is less than i or i is greater than the length of the vector, returns a numarray array of zero elements.
00208 Otherwise it behaves like a list.
00209 """
00210 return self.matrix.__getslice__( self, start, stop, step=1 )
00211
00212
00213 def __setslice__( self, i, j, data ):
00214 """
00215 Writes a numarray array from index i to j to the binary file corresponding to the data_container.
00216 """
00217 return self.matrix.__setslice__( self, i, j, data )
00218
00219
00220
00221
00222 def __add__( self, other ):
00223 """
00224 vec1.__add__(vec2) <==> vec1 + vec2
00225 """
00226 if isinstance( other, aug_vec ):
00227 return aug_vec( self.matrix.A + other.matrix.A )
00228 else:
00229 return aug_vec( self.matrix.A + other )
00230
00231
00232
00233
00234 def __radd__( self, other ):
00235 """
00236 vec1.__radd__(vec2) <==> vec2 + vec1
00237 vec2 may be a scalar or a vector
00238 """
00239 return self.__add__( other )
00240
00241
00242
00243 def __neg__( self ):
00244 """
00245 vec1.__neg__() <==> -vec1
00246 """
00247 return aug_vec( self.callattrs( "__neg__" ) )
00248
00249
00250 def __sub__( self, other ):
00251 """
00252 vec1.__sub__(vec2) <==> vec1 - vec2
00253 vec2 may be a scalar or a vector
00254 """
00255 if isinstance( other, aug_vec ):
00256 return aug_vec( self.matrix.A - other.matrix.A )
00257 else:
00258 return aug_vec( self.matrix.A - other )
00259
00260
00261
00262 def __rsub__( self, other ):
00263 """
00264 vec1.__rsub__(vec2) <==> vec2 - vec1
00265 vec2 may be a scalar or a vector
00266 """
00267 return aug_vec( self.matrix.A + other )
00268
00269
00270 def __div__( self, other ):
00271 """
00272 vec1.__div__(vec2) <==> vec1 / vec2
00273 vec2 may be a scalar or a vector
00274 """
00275 if isinstance( other, aug_vec ):
00276 return aug_vec( self.matrix.A / other.matrix.A )
00277 else:
00278 return aug_vec( self.matrix.A / other )
00279
00280
00281
00282 def __rdiv__( self, other ):
00283 """
00284 vec1.__rdiv__(vec2) <==> vec2 / vec1
00285 vec2 may be a scalar or a vector
00286 """
00287 return aug_vec( other / self.matrix.A )
00288
00289
00290
00291 def __mul__( self, other ):
00292 """
00293 vec1.__mul__(vec2) <==> vec1 * vec2
00294 vec2 may be a scalar or a vector
00295 """
00296 if isinstance( other, aug_vec ):
00297 return aug_vec( self.matrix.A * other.matrix.A )
00298 else:
00299 return aug_vec( self.matrix.A * other )
00300
00301
00302 def __rmul__( self, other ):
00303 """
00304 vec1.__rmul__(vec2) <==> vec2 * vec
00305 """
00306 return aug_vec( self.matrix.A * other )
00307
00308
00309
00310 def __pow__( self, other ):
00311 """
00312 vec1.__pow__(vec2) <==> vec1 ** vec2
00313 vec2 may be a scalar or a vector
00314 """
00315 if isinstance( other, aug_vec ):
00316 return aug_vec( self.matrix.A ** other.matrix.A )
00317 else:
00318 return aug_vec( self.matrix.A ** other )
00319
00320
00321 def __abs__( self ):
00322 """
00323 Vector.__abs__(vec2) <==> abs(vec1)
00324 vec2 may be a scalar or a vector
00325 """
00326 return aug_vec( self.callattrs( "__abs__" ) )
00327
00328 def rms( self ):
00329 """ Returns the root mean square"""
00330 return self.callattrs( "rms" )
00331
00332 def max( self ):
00333 """ Returns the maximum value"""
00334 return self.callattrs( "max" ).max()
00335
00336 def min( self ):
00337 """ Returns the minimum value"""
00338 return self.callattrs( "min" ).min()
00339
00340 def mean( self ):
00341 """ Returns the mean value"""
00342 return self.callattrs( "mean" ).mean( axis=2, dtype=None )
00343
00344 def var( self ):
00345 """ Returns the variance"""
00346 return self.callattrs( "var" ).var( axis=2 )
00347
00348 def sdt( self ):
00349 """ Returns the root"""
00350 return self.callattrs( "sdt" )
00351
00352
00353 def norm( self, lval=2 ):
00354 """ Returns the lval norm of the vector """
00355 return numpy.linalg.norm( self.callattrs( "norm", lval=lval ), lval )
00356
00357
00358
00359 def real( self ):
00360 """
00361 Returns a vector containing the real component of a complex vector.
00362 """
00363 return aug_vec( self.callattrs( "real" ) )
00364
00365
00366 def imag( self ):
00367 """
00368 Returns a vector containing the imaginary component of a complex vector.
00369 """
00370 return aug_vec( self.callattrs( "real" ) )
00371
00372
00373 def thr( self, obj, mode='soft' ):
00374 """
00375 Returns a thresholded vector.
00376 obj - may be a scalar or a vector.
00377 mode - may be 'soft', 'hard' or 'nng'
00378 """
00379 if isinstance( obj, aug_vec ) or hasattr( obj, "__iter__" ):
00380 array_obj = array( obj )
00381 array_obj.resize( self.matrix.shape )
00382 A = self.getattrs( 'thr' )
00383
00384 for i in range( len( A ) ):
00385 for j in range( len( A[i] ) ):
00386 if callable( A[i][j] ):
00387 A[i][j] = A[i][j]( array_obj[i,j],mode=mode )
00388
00389
00390 return aug_vec( A )
00391
00392
00393
00394 def noise( self, mean=0 ):
00395 """
00396 Returns vector with added added random noise.
00397 mean - noise mean
00398 """
00399 return aug_vec( self.callattrs( "noise" , mean=mean ) )
00400
00401
00402 def sort( self, ascmode=False, memsize=None ):
00403 """
00404 Returns a vector with a sorted data set.
00405 """
00406 raise NotImplementedError
00407
00408
00409 def orderstat( self, i ):
00410 """
00411 Returns the ith order statistic of the vector (ith smallest element), i.e. i=0 is smallest, i=1 second smallest, etc.)
00412 Negative indexing starts with the largest element, i.e. i=-1 is largest, i=-2 second largest, etc.
00413 """
00414 raise NotImplementedError
00415
00416
00417
00418
00419 def adj( self, a1=1, a2=2, memsize=100 ):
00420 """
00421 adjose a dataset
00422 """
00423 return aug_vec( self.callattrs( "adj" , a1=a1, a2=a2, memsize=memsize ) )
00424
00425 def setName( self, name, path=None ):
00426 """
00427 Set the name of all of the vectors in this
00428 aug_vec instance.
00429 appends the position of the vector to the end of its name for example:
00430 a 1x1 aug_vec
00431 v.setname( 'v')
00432 is equivalent to
00433 v[0,0].setname( 'v00')
00434 """
00435 A = self.matrix.A
00436 if isinstance(name, (list,tuple,ndarray)):
00437
00438 assert len(name) == len( A ), "%s != %s" %(len(name),len( A ))
00439
00440 it = iter(name)
00441 name_gen = lambda i,j: it.next()
00442 else:
00443 name_gen = lambda i,j: name+"%(i)s%(j)s" %vars()
00444
00445 for i in range( len( A ) ):
00446 for j in range( len( A[i] ) ):
00447 ij_name = name_gen(i,j)
00448 if hasattr( A[i][j], "setName" ):
00449 A[i][j].setName( ij_name, path=path )
00450
00451
00452
00453
00454
00455
00456
00457