00001 """
00002 Todo doc
00003 """
00004
00005 from unittest import TextTestRunner
00006 import sys
00007 import new
00008 import unittest
00009 from numpy import ndarray,all,array
00010
00011 __copyright__ = """
00012 Copyright 2008 Sean Ross-Ross
00013 """
00014 __license__ = """
00015 This file is part of SLIMpy .
00016
00017 SLIMpy is free software: you can redistribute it and/or modify
00018 it under the terms of the GNU Lesser General Public License as published by
00019 the Free Software Foundation, either version 3 of the License, or
00020 (at your option) any later version.
00021
00022 SLIMpy is distributed in the hope that it will be useful,
00023 but WITHOUT ANY WARRANTY; without even the implied warranty of
00024 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00025 GNU Lesser General Public License for more details.
00026
00027 You should have received a copy of the GNU Lesser General Public License
00028 along with SLIMpy . If not, see <http://www.gnu.org/licenses/>.
00029 """
00030
00031
00032 class DotTester( object ):
00033
00034 __shared_state = {}
00035 opers = set()
00036
00037 def __init__( self):
00038
00039 self.__dict__ = self.__shared_state
00040
00041 def clear( self ):
00042 self.__shared_state = {}
00043
00044 def addLinearOp( self, linop ):
00045
00046
00047 test = False
00048 for oper in self.opers:
00049 if isinstance(oper, ndarray) ^ isinstance(linop, ndarray):
00050 continue
00051 elif isinstance(oper, ndarray) and isinstance(linop, ndarray):
00052 test = all(oper == linop)
00053 else:
00054 test = bool( oper == linop )
00055
00056 if test:
00057 return
00058 else:
00059 self.opers.add( linop )
00060
00061
00062 def buildTestSuite( self ,places=11):
00063
00064 suite = unittest.TestSuite()
00065 testloader = unittest.TestLoader()
00066 loadtest = testloader.loadTestsFromTestCase
00067
00068 for oper in self.opers:
00069 dottest = new.classobj( str( oper ), ( DotTestFixture, ), {'oper':oper,'places':places} )
00070 test = loadtest( dottest )
00071 suite.addTest( test )
00072
00073 return suite
00074
00075 def __str__( self ):
00076 ret = ""
00077 msg = "Dottest:\n +"
00078
00079 for oper in self.opers:
00080 ret += " +"+str( oper ) +'\n'
00081
00082 return msg + ret
00083
00084
00085
00086 class DotTestFixture( unittest.TestCase ):
00087
00088 def calcNorms( self, tmp1, tmp2 ):
00089 norm1 = tmp1.norm( 1 )
00090 norm2 = tmp2.norm( 1 )
00091 return norm1, norm2
00092
00093 oper = None
00094 places = 11
00095
00096 def setUp( self ):
00097 """
00098
00099 """
00100
00101
00102
00103
00104 def tearDown( self ):
00105
00106
00107
00108
00109
00110
00111 pass
00112
00113
00114 def testLinearOperator( self ):
00115 """
00116
00117 """
00118
00119 print "-"*50
00120 print str( self.oper )
00121 if self.oper is None:
00122 raise NotImplementedError( 'The DotTestFixture class must be '
00123 'subclassed and the "oper" field sust be set' )
00124
00125 A = self.oper.copy( )
00126
00127 domain = A.domain()
00128 range = A.range()
00129
00130 domainNoise = domain.noise()
00131
00132 if domain.isReal() and range.isComplex():
00133 rangeNoise = A * domain.noise()
00134 else:
00135 rangeNoise = range.noise()
00136
00137 msg = "\n\nInitial data is not in the domain of '%s' \n"
00138
00139 self.assertTrue( domainNoise in A.domain( ) , msg %( A.domain() ) )
00140 msg = "\n\nInitial transformed data is not in the range of '%s' \n"
00141 self.assertTrue( rangeNoise in A.range() , msg %( A.range() ) )
00142
00143 trans = A * domainNoise
00144
00145 inv = A.H * rangeNoise
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156 norm1 = rangeNoise.H * trans
00157 norm2 = inv.H * domainNoise
00158
00159 ratio = abs( norm1.item()/norm2.item() )
00160
00161
00162 if hasattr(self, 'ratio_list'):
00163 self.ratio_list.append(ratio)
00164
00165 places = self.places
00166
00167 msg = ("Linear Operator failed the dot test with ratio: "
00168 "%(ratio)s\n%(norm1)s != %(norm2)s "
00169 "failed within %(places)s places" %vars())
00170
00171
00172
00173
00174
00175
00176 self.assertAlmostEquals( ratio, 1 , places=places, msg=msg )
00177 print norm1.data, "==", norm2.data
00178 print "ratio:",ratio
00179
00180 def generateNoisyData( self, space ):
00181
00182 if space.isComplex():
00183 cspace = space.copy()
00184
00185 cspace['data_type'] = 'float'
00186
00187 cnoise = cspace.zeros().noise()
00188 rnoise = cspace.zeros().noise()
00189
00190 from slimpy_base.api.functions.functions import cmplx
00191
00192 noise = cmplx( rnoise, cnoise )
00193
00194 else:
00195 noise = space.zeros().noise()
00196
00197
00198 return noise
00199
00200 def DotTest( oper, percision=7, numtests=1, expected_mean=1 ):
00201 """
00202 Dottest a Linear Operator
00203
00204 @details
00205 s.t.
00206 @f$
00207 \langle Ay,x \rangle \approx \langle A^{H}x, y \rangle
00208 @f$
00209 within @a percision digits.
00210 where @a A is in @a opers and x and y are created by
00211 @ref slimpy_base.Core.User.Structures.VectorSpace.VectorSpace.noise "A.range.noise( )"
00212 and
00213 @ref slimpy_base.Core.User.Structures.VectorSpace.VectorSpace.noise "A.domain.noise( )"
00214 respectivly.
00215
00216 @param opers may be a linear operator or a
00217 list of linear operators
00218 @param percision the preceition to run the test at, determining a pass or a fail.
00219 """
00220
00221 suite = unittest.TestSuite()
00222 testloader = unittest.TestLoader()
00223 loadtest = testloader.loadTestsFromTestCase
00224
00225 ratio_list = []
00226 for i in range(numtests):
00227 dottest = new.classobj( str( oper ), ( DotTestFixture, ), {'oper':oper,'places':percision,'ratio_list':ratio_list} )
00228 test = loadtest( dottest )
00229 suite.addTest( test )
00230
00231 testRunner = TextTestRunner( sys.stdout, 1, 1 )
00232 testRunner.run( suite )
00233
00234 ratarray = array( ratio_list )
00235 avrat = sum( ratarray)/ len(ratarray)
00236 varrat = sum((ratarray-1)**2)
00237 avvar = (avrat-1)**2
00238 print "Summary: "
00239 print " avg ratio: %(avrat).2e" %vars()
00240 print " avg var : %(avvar).2e" %vars()
00241 print " varience : %(varrat).2e" %vars()
00242
00243
00244
00245