def woodbury(X, Ainv, m, up = True): ''' Does a rank-k adjustment of Ainv using the woodbury matrix identity (A + XX^H)^(-1) = A^(-1) - (A^(-1)X ( I + X^(H)A^(-1)X )^(-1)X^(H)A^(-1)) If up == True: A rank update is performed, otherwise we do a rank degrade NB! Not finished ''' factor = 1 if up != True: factor = -1 XH = mynp.conjugatetranspose(X) XHAinv = mynp.dot(XH, Ainv) AinvX = mynp.dot(Ainv, XH) XHAinvX = mynp.dot(XHAinv, X) IXHAinvX = mynp.eye(m) + (factor * XHAinvX) # TODO: inv_IXHAinvX = we need to invert IXHAinvX!!! AinvX_IXHAinvX_XHAinv = mynp.dot(mynp.dot(AinvX, IXHAinvX), XHAinv) newAinv = Ainv + (-factor * AinvX_IXHAinvX_XHAinv) return newAinv
def woodbury(X, Ainv, m, up=True): ''' Does a rank-k adjustment of Ainv using the woodbury matrix identity (A + XX^H)^(-1) = A^(-1) - (A^(-1)X ( I + X^(H)A^(-1)X )^(-1)X^(H)A^(-1)) If up == True: A rank update is performed, otherwise we do a rank degrade NB! Not finished ''' factor = 1 if up != True: factor = -1 XH = mynp.conjugatetranspose(X) XHAinv = mynp.dot(XH, Ainv) AinvX = mynp.dot(Ainv, XH) XHAinvX = mynp.dot(XHAinv, X) IXHAinvX = mynp.eye(m) + (factor * XHAinvX) # TODO: inv_IXHAinvX = we need to invert IXHAinvX!!! AinvX_IXHAinvX_XHAinv = mynp.dot(mynp.dot(AinvX, IXHAinvX), XHAinv) newAinv = Ainv + (-factor * AinvX_IXHAinvX_XHAinv) return newAinv
def shermanMorrison(x, Ainv, m, up = True): ''' Does a rank-1 adjustment of Ainv using the Sherman-Morrison formula (A + xx^H)^(-1) = A^(-1) - (A^(-1)xx^(H)A^(-1)) / (1 + x^(H)A^(-1)x) if (1 + x^(H)A^(-1)x) != 0. Ainv is a matrix of size m*m x is a column vector of length m If up == True: A rank update is performed, otherwise we do a rank degrade. ''' factor = 1 if up != True: factor = -1 xH = x.conjugate() Ainvx = mynp.dot(Ainv, x) xHAinv = mynp.dot(xH, Ainv) xHAinvx = mynp.dot(xH, mynp.dot(Ainv, x)) # memory layout impose this product rather than reusing xHAinv (the result here is a scalar) numerator = mynp.outer(Ainvx, xHAinv) denominator = 1 + factor * xHAinvx if abs(denominator) == 0: raise Exception('Denominator is 0 in Sherman Morrison formula') return Ainv - ( (factor/denominator) * numerator )
def shermanMorrison(x, Ainv, m, up=True): ''' Does a rank-1 adjustment of Ainv using the Sherman-Morrison formula (A + xx^H)^(-1) = A^(-1) - (A^(-1)xx^(H)A^(-1)) / (1 + x^(H)A^(-1)x) if (1 + x^(H)A^(-1)x) != 0. Ainv is a matrix of size m*m x is a column vector of length m If up == True: A rank update is performed, otherwise we do a rank degrade. ''' factor = 1 if up != True: factor = -1 xH = x.conjugate() Ainvx = mynp.dot(Ainv, x) xHAinv = mynp.dot(xH, Ainv) xHAinvx = mynp.dot( xH, mynp.dot(Ainv, x) ) # memory layout impose this product rather than reusing xHAinv (the result here is a scalar) numerator = mynp.outer(Ainvx, xHAinv) denominator = 1 + factor * xHAinvx if abs(denominator) == 0: raise Exception('Denominator is 0 in Sherman Morrison formula') return Ainv - ((factor / denominator) * numerator)
def testComplexMatrixVectorMul(self): errstr = 'Error in result returned by matrix vector multiplication' x = mynp.dot(self.complexA, self.complexb) self.assertListEqual(x.tolist(), self.complexAb.tolist(), errstr + ' (square complex matrix)') x = mynp.dot(self.complexA[0:2], self.complexb) self.assertListEqual(x[0:2].tolist(), self.complexAb[0:2].tolist(), errstr + ' (non-square complex matrix)')
def testMatrixVectorMul(self): errstr = 'Error in result returned by matrix vector multiplication' x = mynp.dot(self.A, self.b2) self.assertListEqual(x.tolist(), self.Ab2.tolist(), errstr + ' (Square matrix)') x = mynp.dot(self.A, self.b1) self.assertListEqual(x.tolist(), self.Ab1.tolist(), errstr + ' (Square matrix)') x = mynp.dot(self.A[0:2], self.b2) self.assertListEqual(x.tolist(), self.Ab2[0:2].tolist(), errstr + ' (non-square matrix)')
def testIterativBuildRinv(self): M = self.sonardata_n L = 24 Yavg = 5 d = 0 # diagonal loading as a function of matrix trace is not supported. Use the squared sum of channel data (i.e. the total energy) invR = wb.iterativeBuildRinv(self.sonardata_ar, M, L, Yavg, d) invRa = mynp.dot(invR, self.sonardata_a) self.assertMatrixAlmosteEqual(self.sonardata_Ria, invRa, 7) x = mynp.ones(M, dtype=complex) invR = wb.iterativeBuildUpRinv(invR, x, M, L) invR = wb.iterativeBuildDownRinv(invR, x, M, L) invRa = mynp.dot(invR, self.sonardata_a) self.assertMatrixAlmosteEqual(self.sonardata_Ria, invRa, 7)
def processData(self): if VERBOSE: print 'Start processing image...' if self.multiFile: self.s = System(self.dataTag + ' %d' % (self.image_idx.value + 1)) self.Xd_i = self.s.data.Xd else: self.Xd_i = self.Xd[self.image_idx.value, :, :, :].copy() self.Xd_i = self.Xd_i[self.sliceAngleStart.value:self.sliceAngleEnd. value:self.sliceAngleStep.value, self.sliceRangeStart.value:self.sliceRangeEnd. value:self.sliceRangeStep.value, self.sliceElementStart.value:self.sliceElementEnd .value:self.sliceElementStep.value] self.Nx = self.Xd_i.shape[0] # No. beams self.Ny = self.Xd_i.shape[1] # No. range samples self.Nm = self.Xd_i.shape[2] # No. channels self.angles = self.s.data.angles.squeeze() self.angles = self.angles[self.sliceAngleStart.value:self.sliceAngleEnd .value:self.sliceAngleStep.value] self.ranges = self.s.data.ranges.squeeze() self.ranges = self.ranges[self.sliceRangeStart.value:self.sliceRangeEnd .value:self.sliceRangeStep.value] # Make delay and sum image if self.apod.value is 1: self.das_w = np.hamming(self.Nm) self.das_w_sub = np.hamming(self.L.value) else: self.das_w = np.ones(self.Nm) self.das_w_sub = np.ones(self.L.value) self.img_das = np.dot(self.Xd_i, self.das_w) / self.Nm if self.K.value > 0: self.img_das = self.img_das[:, self.K.value:-self.K. value] # truncate to get equal dim on das and capon image # init sub/beam-space matrix if self.Nb.value > 0: self.B = np.ones((self.Nb.value, self.L.value)) else: self.B = np.array([0]) # Make capon image res_gpu = getCaponCUDA.getCaponCUDAPy(self.Xd_i, 10.0**self.d.value, self.L.value, self.K.value, self.B, False, False) self.img_capon = res_gpu[0] self.capon_weights = res_gpu[2] #self.img_capon = self.img_das if VERBOSE: print 'getCaponCUDA return code: ', res_gpu[3] print 'done.'
def calcBeamPatternLinearArray(self, w, M, spacing, thetas, steering_angle=0, takePowerAndNormalize=False): x_el = np.linspace( -(M-1)/(2.0/spacing), (M-1)/(2.0/spacing), M ) W_matrix = np.exp(-1j * np.outer(2*np.pi*(np.sin(thetas) - np.sin(steering_angle)), x_el)) W = np.dot(W_matrix , w) if takePowerAndNormalize: W = W*W.conj() W = W / W.max() return W
def testRTransposedTimesRIsEqualA(self): R = md.cholesky(self.A, self.n) RT = mynp.conjugatetranspose(R) A = mynp.dot(RT, R) for i in range(self.n): for j in range(self.n): self.assertAlmostEqual(self.A[i][j].tolist(), A[i][j].tolist(), 15, "expected " + str(self.A[i][j]) + " was " + str(A[i][j]))
def testRTransposedTimesRIsEqualA(self): R = md.cholesky(self.A, self.n) RT = mynp.conjugatetranspose(R) A = mynp.dot(RT, R) for i in range(self.n): for j in range(self.n): self.assertAlmostEqual( self.A[i][j].tolist(), A[i][j].tolist(), 15, "expected " + str(self.A[i][j]) + " was " + str(A[i][j]))
def processData(self): if VERBOSE: print 'Start processing image...' if self.multiFile: self.s = System(self.dataTag + ' %d'%(self.image_idx.value+1)) self.Xd_i = self.s.data.Xd else: self.Xd_i = self.Xd[self.image_idx.value, :, :, :].copy() self.Xd_i = self.Xd_i[self.sliceAngleStart.value:self.sliceAngleEnd.value:self.sliceAngleStep.value, self.sliceRangeStart.value:self.sliceRangeEnd.value:self.sliceRangeStep.value, self.sliceElementStart.value:self.sliceElementEnd.value:self.sliceElementStep.value]; self.Nx = self.Xd_i.shape[0] # No. beams self.Ny = self.Xd_i.shape[1] # No. range samples self.Nm = self.Xd_i.shape[2] # No. channels self.angles = self.s.data.angles.squeeze() self.angles = self.angles[self.sliceAngleStart.value:self.sliceAngleEnd.value:self.sliceAngleStep.value] self.ranges = self.s.data.ranges.squeeze() self.ranges = self.ranges[self.sliceRangeStart.value:self.sliceRangeEnd.value:self.sliceRangeStep.value] # Make delay and sum image if self.apod.value is 1: self.das_w = np.hamming(self.Nm) self.das_w_sub = np.hamming(self.L.value) else: self.das_w = np.ones(self.Nm) self.das_w_sub = np.ones(self.L.value) self.img_das = np.dot(self.Xd_i, self.das_w) / self.Nm if self.K.value > 0: self.img_das = self.img_das[:,self.K.value:-self.K.value]# truncate to get equal dim on das and capon image # init sub/beam-space matrix if self.Nb.value > 0: self.B = np.ones((self.Nb.value, self.L.value)) else: self.B = np.array([0]) # Make capon image res_gpu = getCaponCUDA.getCaponCUDAPy(self.Xd_i, 10.0**self.d.value, self.L.value, self.K.value, self.B, False, False) self.img_capon = res_gpu[0] self.capon_weights = res_gpu[2] #self.img_capon = self.img_das if VERBOSE: print 'getCaponCUDA return code: ', res_gpu[3] print 'done.'
def calcBeamPatternLinearArray(self, w, M, spacing, thetas, steering_angle=0, takePowerAndNormalize=False): x_el = np.linspace(-(M - 1) / (2.0 / spacing), (M - 1) / (2.0 / spacing), M) W_matrix = np.exp( -1j * np.outer(2 * np.pi * (np.sin(thetas) - np.sin(steering_angle)), x_el)) W = np.dot(W_matrix, w) if takePowerAndNormalize: W = W * W.conj() W = W / W.max() return W
def solveBiCG(A, b, x0, tol, itr): ''' Solves the complex linear system Ax = b using the complex-biconjugate-gradient method Arguments: A -- Coefficient matrix b -- Right-side vector x0 -- Initial solution (default: 0-vector) tol -- Stop solver when error is less than tol (default: 0) itr -- Stop solver after itr iterations -- default ''' # Check arguments m,n = len(A),len(A[0]) if m != n: raise Exception('Coefficient matrix is not square') if len(b) != n: raise Exception('Dimension mismatch between A and b') x = x0 # make origin as starting point if no x is passed # Calculate initial residual r = b - Ax0 and search direction p r0 = b - np.dot(A, x) r = r0 normr0 = np.euclidnorm(r0) if (np.euclidnorm(r) / normr0) <= tol: # break if error is less-than tolerance. # TODO: Should also test bir return x p = np.array(r) # init biresidual and bidirection bir = r.conjugate() bip = p.conjugate() numerator,denominator = 0,0 alpha,betha = 0,0 AH = np.conjugatetranspose(A) # Simplification: since A is Hermitian and semi-positive definite in our case, we can avoid this step... if itr <= 0 or itr > m: itr = m for i in range(itr): # Calculate common matrix-vector products Ap = np.dot(A, p) AHbip = np.dot(AH, bip) # Calculate step-length parameter numerator = np.vdot(bir, r) denominator = np.vdot(bip, Ap) alpha = numerator / denominator # Obtain new solution x = x + (alpha * p) # Calculate new residual and biresidual # r = r - (alpha * Ap) for i in range(m): r[i] = r[i] - alpha * Ap[i] # Calculate new residual and biresidual if np.euclidnorm(r) / normr0 <= tol: # TODO: Should also test bir return x bir = bir - (alpha.conjugate() * AHbip) # Calculate the biconjugacy coefficient numerator = np.vdot(AHbip, r) denominator = np.vdot(bip, Ap) betha = -1.0 * (numerator / denominator) # Obtain new search and bi-search-direction p = r + (betha * p) bip = bir + (betha.conjugate() * bip) return x
def testMatrixMulSquareATimesA(self): C = mynp.dot(self.A, self.A) self.assertEqual(self.AA.tolist(), C.tolist())
def beamspace(B, x): ''' Transform/beamform the given data vector x with the matrix B ''' ''' This is just a wrapper for a standard matrix-vector multiplication ''' return mynp.dot(B, x)
def solveBiCG(A, b, x0, tol, itr): ''' Solves the complex linear system Ax = b using the complex-biconjugate-gradient method Arguments: A -- Coefficient matrix b -- Right-side vector x0 -- Initial solution (default: 0-vector) tol -- Stop solver when error is less than tol (default: 0) itr -- Stop solver after itr iterations -- default ''' # Check arguments m, n = len(A), len(A[0]) if m != n: raise Exception('Coefficient matrix is not square') if len(b) != n: raise Exception('Dimension mismatch between A and b') x = x0 # make origin as starting point if no x is passed # Calculate initial residual r = b - Ax0 and search direction p r0 = b - np.dot(A, x) r = r0 normr0 = np.euclidnorm(r0) if (np.euclidnorm(r) / normr0) <= tol: # break if error is less-than tolerance. # TODO: Should also test bir return x p = np.array(r) # init biresidual and bidirection bir = r.conjugate() bip = p.conjugate() numerator, denominator = 0, 0 alpha, betha = 0, 0 AH = np.conjugatetranspose( A ) # Simplification: since A is Hermitian and semi-positive definite in our case, we can avoid this step... if itr <= 0 or itr > m: itr = m for i in range(itr): # Calculate common matrix-vector products Ap = np.dot(A, p) AHbip = np.dot(AH, bip) # Calculate step-length parameter numerator = np.vdot(bir, r) denominator = np.vdot(bip, Ap) alpha = numerator / denominator # Obtain new solution x = x + (alpha * p) # Calculate new residual and biresidual # r = r - (alpha * Ap) for i in range(m): r[i] = r[i] - alpha * Ap[ i] # Calculate new residual and biresidual if np.euclidnorm(r) / normr0 <= tol: # TODO: Should also test bir return x bir = bir - (alpha.conjugate() * AHbip) # Calculate the biconjugacy coefficient numerator = np.vdot(AHbip, r) denominator = np.vdot(bip, Ap) betha = -1.0 * (numerator / denominator) # Obtain new search and bi-search-direction p = r + (betha * p) bip = bir + (betha.conjugate() * bip) return x
def setUp(self): self.n = 3 self.A = np.array([[2.0, -1.0, 0.0], [-1.0, 2.0, -1.0], [0.0, -1.0, 2.0]],dtype=complex) self.A2 = np.array([[4.0, -2.0, 0.0], [-2.0, 4.0, -2.0], [0.0, -2.0, 4.0]],dtype=complex) self.R = np.array([[1.414213562373095, -0.707106781186547, 0.0], [0.0, 1.224744871391589, -0.816496580927726], [0.0, 0.0, 1.154700538379252]],dtype=complex) self.AA = np.array([[5, -4, 1], [-4, 6, -4], [1, -4, 5]],dtype=complex) self.B = np.array([[1, 2, 3], [1, 2, 3], [1, 2, 3]],dtype=complex) self.BT = np.array([[1, 1, 1], [2, 2, 2], [3, 3, 3]],dtype=complex) self.b1 = np.array([1.0, 1.0, 1.0],dtype=complex) self.x1 = np.array([3.0/2, 2.0, 3.0/2],dtype=complex) self.b2 = np.array([1, 2, 3],dtype=complex) self.x2 = np.array([5.0/2, 4, 7.0/2],dtype=complex) self.C = np.array([[1, 2, 3], [0, 1, 1], [0, 0, 1]],dtype=complex) self.b1c = np.array([1, 1, 1],dtype=complex) self.x1c = np.array([-2, 0, 1],dtype=complex) self.x1cT = np.array([1, -1, -1],dtype=complex) self.x0_zero = np.zeros((3,), dtype=complex) self.Ab2 = np.array([0, 0, 4],dtype=complex) self.Ab1 = np.array([1, 0, 1],dtype=complex) self.Ab1b1T = np.array([[3, 1, 3], [1, 6, 5], [3, 5, 11]],dtype=complex) self.invA = np.array([[0.750, 0.50, 0.250], [0.50, 1.0, 0.50], [0.250, 0.50, 0.750]],dtype=complex) self.invAb1b1T = np.array([[0.465909090909091, 0.045454545454545, -0.147727272727273], [0.045454545454545, 0.272727272727273, -0.136363636363636], [-0.147727272727273, -0.136363636363636, 0.193181818181818]],dtype=complex) self.complexA = np.array([[2.0, 3.0 + 1.0j, 2.0 - 2.0j], [3.0 - 1.0j, 9.0, -2.0j], [2.0 + 2.0j, 2.0j, 14.0]], dtype=complex) self.complexR = np.array([[1.414213562373095, 2.121320343559642 + 0.707106781186547j, 1.414213562373095 - 1.414213562373095j], [0.0, 2.0, -1.0 + 1.0j], [0.0, 0.0, 2.828427124746190]], dtype=complex) self.complexb = np.array([1.0, 1.0 + 1.0j, 1.0 - 2.0j], dtype=complex) self.complexy = np.array([0.707106781186547 - 0.0j, -0.250 + 0.750j, -0.353553390593273 - 0.883883476483184j], dtype=complex) self.complexx = np.array([1.593749999999999 - 0.06250j, -0.343750 + 0.281250j, -0.1250 - 0.31250j], dtype=complex) self.complexAb = np.array([2.0 - 2.0j, 8.0 + 6.0j, 14.0 - 24.0j], dtype=complex) self.but4 = np.array([[0.5]*4, [0.5, -0.5j, -0.5, 0.5j], [0.5, -0.5]*2, [0.5, 0.5j, -0.5, -0.5j]], dtype=complex) self.but3 = np.array([[0.577350269189626, 0.577350269189626, 0.577350269189626], [0.577350269189626, -0.288675134594813 - 0.50j, -0.288675134594813 + 0.50j], [0.577350269189626, -0.288675134594813 + 0.50j, -0.288675134594813 - 0.50j]], dtype=complex) self.bsComplexb = np.array([1.732050807568878 - 0.577350269189626j, 1.50 + 0.288675134594813j], dtype=complex) self.diag = 0.2 self.x = np.array([1.0, 1.0 + 1.0j, 1.0 - 2.0j, 2.0 + 1.0j], dtype=complex) self.complexAbbH = np.array([[10.0, 11.0 + 1.0j, 10.0 - 2.0j], [11.0 - 1.0j, 17.0, 8.0 - 2.0j], [10.0 + 2.0j, 8.0 + 2.0j, 22.0]], dtype=complex) self.complexInvAbbH = np.array([[1.067010309278351, -0.407216494845361 - 0.015463917525773j, -0.190721649484536 + 0.020618556701031j], [-0.407216494845361 + 0.015463917525773j, 0.247422680412371, 0.077319587628866 - 0.015463917525773j], [-0.190721649484536 - 0.020618556701031j, 0.077319587628866 + 0.015463917525773j, 0.087628865979381]], dtype=complex) self.complexInvA = np.array([[1.906250, -0.593750 - 0.156250j, -0.250 + 0.18750j], [-0.593750 + 0.156250j, 0.31250, 0.06250 - 0.06250j], [-0.250 - 0.18750j, 0.06250 + 0.06250j, 0.1250]], dtype=complex) self.complexA4x4 = np.array([[22.0, 8.0, 11.0 - 11.0j, 22.0 - 7.0j], [8.0, 22.0, 17.0 - 2.0j, 11.0 - 7.0j], [11.0 + 11.0j, 17.0 + 2.0j, 45.0, 23.0 - 5.0j], [22.0 + 7.0j, 11.0 + 7.0j, 23.0 + 5.0j, 37.0]], dtype=complex) self.U4x4 = np.array([[1.0000, 0.3636, 0.50 - 0.50j, 1.0 - 0.3182j], [0.0, 1.0, 0.6810 + 0.1048j, 0.1571 - 0.2333j], [0.0, 0.0, 1.0, 0.2776 - 0.3670j], [0.0, 0.0, 0.0, 1.0]], dtype=complex) self.D4x4 = np.array([22.0, 19.0909, 24.9381, 5.9806]) self.sonardata_R = np.array(np.load('./data/data_R.npy')) # created without diagonal loading self.sonardata_a = np.array(np.load('./data/data_a.npy')) self.sonardata_Ria = np.array(np.load('./data/data_Ria.npy')) self.sonardata_ar = np.array(np.load('./data/data_ar.npy')) self.sonardata_n = 32 # random data for testing self.L = L = 24 self.d = d = 100 U = np.triu(np.random.randn(L,L) + np.random.randn(L,L)*1j) + np.eye(L)*d self.randA = np.dot(U.conjugate().T, U) self.randb = np.random.randn(L) + np.random.randn(L)*1j