def test_smw_formula_spv(self): """check the use of the smw formula with sparse v for the inverse of A-UV with v sparse""" # check the branch with direct solves AuvInvZ = lau.app_smw_inv(self.A, umat=self.U, vmat=self.Vsp, rhsa=self.Z, Sinv=None) AAinvZ = self.A * AuvInvZ - np.dot(self.U, self.Vsp * AuvInvZ) self.assertTrue(np.allclose(AAinvZ, self.Z)) # check the branch where A comes as LU alusolve = spsla.factorized(self.A) AuvInvZ = lau.app_smw_inv(alusolve, umat=self.U, vmat=self.Vsp, rhsa=self.Z, Sinv=None) AAinvZ = self.A * AuvInvZ - np.dot(self.U, self.Vsp * AuvInvZ) self.assertTrue(np.allclose(AAinvZ, self.Z))
def test_smw_formula_complex(self): """check the use of the smw formula for the inverse of A-UV""" # check the branch with direct solves apoi = self.A + 1j * self.M AuvInvZ = lau.app_smw_inv(apoi, umat=self.U, vmat=self.V, rhsa=self.Z, Sinv=None) AAinvZ = apoi * AuvInvZ - np.dot(self.U, np.dot(self.V, AuvInvZ)) self.assertTrue(np.allclose(AAinvZ, self.Z)) # check the branch where A comes as LU alusolve = spsla.factorized(apoi) AuvInvZ = lau.app_smw_inv(alusolve, umat=self.U, vmat=self.V, rhsa=self.Z, Sinv=None) AAinvZ = apoi * AuvInvZ - np.dot(self.U, np.dot(self.V, AuvInvZ)) self.assertTrue(np.allclose(AAinvZ, self.Z))
def test_smw_formula_krypy(self): """check the smw using krypy's gmres """ AuvInvZ = lau.app_smw_inv(self.A, umat=self.U, vmat=self.V, rhsa=self.Z, krylov=True, krpslvprms=self.krpslvprms) AAinvZ = self.A * AuvInvZ - np.dot(self.U, np.dot(self.V, AuvInvZ)) print np.linalg.norm(AAinvZ - self.Z) self.assertTrue(np.allclose(AAinvZ, self.Z))
def test_smw_formula(self): """check the use of the smw formula for the inverse of A-UV""" # check the branch with direct solves AuvInvZ = lau.app_smw_inv(self.A, umat=self.U, vmat=self.V, rhsa=self.Z, Sinv=None) AAinvZ = self.A * AuvInvZ - np.dot(self.U, np.dot(self.V, AuvInvZ)) self.assertTrue(np.allclose(AAinvZ, self.Z)) # check the branch where A comes as LU alusolve = spsla.factorized(self.A) AuvInvZ = lau.app_smw_inv(alusolve, umat=self.U, vmat=self.V, rhsa=self.Z, Sinv=None) AAinvZ = self.A * AuvInvZ - np.dot(self.U, np.dot(self.V, AuvInvZ)) self.assertTrue(np.allclose(AAinvZ, self.Z))
def solve_proj_lyap_stein(amat=None, jmat=None, wmat=None, mmat=None, umat=None, vmat=None, transposed=False, adi_dict=dict(adi_max_steps=150, adi_newZ_reltol=1e-8), nwtn_adi_dict=None, **kw): """ approximates the solution X to the projected lyap equation [A-UV].T*X*M + M.T*X*[A-UV] + J.T*Y*M + M.T*Y.T*J = -W*W.T J*X*M = 0 and M.T*X*J.T = 0 by considering the equivalent Stein eqns and computing the first members of the series converging to X We use the SMW formula: (A-UV).-1 = A.-1 + A.-1*U [ I - V A.-1 U].-1 A.-1 for the transpose: (A-UV).-T = A.-T + A.-T*Vt [ I - Ut A.-T Vt ].-1 A.-T = (A.T - Vt Ut).-1 see numOptAff.pdf """ if nwtn_adi_dict is not None: adi_dict = nwtn_adi_dict # so we can pass the same dicts to lyap and ric solve if transposed: At, Mt = amat, mmat else: At, Mt = amat.T, mmat.T # TODO: compute optimal shifts try: ms = adi_dict['ms'] except KeyError: ms = [-30.0, -20.0, -10.0, -5.0, -3.0, -1.0] if adi_dict['verbose']: print ('\nAdishifts: {0} ').format(ms) NZ = wmat.shape[0] def get_atmtlu(At, Mt, jmat, ms): """compute the LU of the projection matrix """ NP = jmat.shape[0] sysm = sps.vstack([sps.hstack([At + ms.conjugate() * Mt, -jmat.T]), sps.hstack([jmat, sps.csr_matrix((NP, NP))])], format='csc') return spsla.factorized(sysm) def _app_projinvz(Z, At=None, Mt=None, jmat=None, ms=None, atmtlu=None): if atmtlu is None: atmtlu = get_atmtlu(At, Mt, jmat, ms) NZ = Z.shape[0] Zp = np.zeros(Z.shape) zcol = np.zeros(NZ + jmat.shape[0]) for ccol in range(Z.shape[1]): if sps.isspmatrix(Z): zcol[:NZ] = Z[:NZ, ccol].todense().flatten() else: zcol[:NZ] = Z[:NZ, ccol] Zp[:, ccol] = atmtlu(zcol)[:NZ] return Zp, atmtlu adi_step = 0 rel_newZ_norm = 2 adi_rel_newZ_norms = [] atmtlulist = [] for mu in ms: atmtlumu = get_atmtlu(At, Mt, jmat, mu) atmtlulist.append(atmtlumu) if umat is not None and vmat is not None: # preps to apply the smw formula # adding zeros to the coefficients to fit the # saddle point systems vmate = np.hstack([vmat, np.zeros((vmat.shape[0], jmat.shape[0]))]) if sps.isspmatrix(umat): umate = sps.vstack([umat, sps.csr_matrix((jmat.shape[0], umat.shape[1]))]) else: umate = np.vstack([umat, np.zeros((jmat.shape[0], umat.shape[1]))]) stinvlist = [] for ncurmu, mu in enumerate(ms): stinvlist.append(lau.get_Sinv_smw(atmtlulist[ncurmu], umat=vmate.T, vmat=umate.T)) # Start the ADI iteration We = np.vstack([wmat, np.zeros((jmat.shape[0], wmat.shape[1]))]) Z = lau.app_smw_inv(atmtlulist[0], umat=vmate.T, vmat=umate.T, rhsa=np.sqrt(-2 * ms[0].real) * We, Sinv=stinvlist[0])[:NZ, :] ufac = Z u_norm_sqrd = np.linalg.norm(Z) ** 2 muind = 1 muind = np.mod(muind, len(ms)) while adi_step < adi_dict['adi_max_steps'] and \ rel_newZ_norm > adi_dict['adi_newZ_reltol']: Ze = np.vstack([Mt*Z, np.zeros((jmat.shape[0], wmat.shape[1]))]) Zi = lau.app_smw_inv(atmtlulist[muind], umat=vmate.T, vmat=umate.T, rhsa=Ze, Sinv=stinvlist[muind])[:NZ, :] Z = np.sqrt(ms[muind].real / ms[muind-1].real) *\ (Z - (ms[muind] + ms[muind-1].conjugate()) * Zi) z_norm_sqrd = np.linalg.norm(Z) ** 2 u_norm_sqrd = u_norm_sqrd + z_norm_sqrd ufac = np.hstack([ufac, Z]) rel_newZ_norm = np.sqrt(z_norm_sqrd / u_norm_sqrd) # np.linalg.norm(Z)/np.linalg.norm(ufac) adi_step += 1 muind = np.mod(muind+1, len(ms)) adi_rel_newZ_norms.append(rel_newZ_norm) try: if adi_dict['check_lyap_res'] and np.mod(adi_step, 10) == 0: sqrdprolyares = \ comp_proj_lyap_res_norm(Z, amat=amat, mmat=mmat, wmat=wmat, jmat=jmat, umat=umat, vmat=vmat) print 'adistep ', adi_step print 'cur proj lyap res: ', np.sqrt(sqrdprolyares) print 'rel Z norm: \n', rel_newZ_norm except KeyError: pass # no such option specified try: if adi_dict['verbose']: print ('Number of ADI steps {0} -- \n' + 'Relative norm of the update {1}' ).format(adi_step, rel_newZ_norm) print 'sqrd norm of Z: {0}'.format(u_norm_sqrd) except KeyError: pass # no verbosity specified - nothing is shown else: Z = _app_projinvz(np.sqrt(-2*ms[0].real)*wmat, jmat=jmat, atmtlu=atmtlulist[0])[0] ufac = Z u_norm_sqrd = np.linalg.norm(Z) ** 2 muind = 1 muind = np.mod(muind, len(ms)) while adi_step < adi_dict['adi_max_steps'] and \ rel_newZ_norm > adi_dict['adi_newZ_reltol']: Zi = _app_projinvz(Mt*Z, jmat=jmat, atmtlu=atmtlulist[muind])[0] Z = np.sqrt(ms[muind].real / ms[muind-1].real) *\ (Z - (ms[muind] + ms[muind-1].conjugate()) * Zi) ufac = np.hstack([ufac, Z]) z_norm_sqrd = np.linalg.norm(Z) ** 2 u_norm_sqrd = u_norm_sqrd + z_norm_sqrd rel_newZ_norm = np.sqrt(z_norm_sqrd / u_norm_sqrd) adi_step += 1 muind = np.mod(muind+1, len(ms)) adi_rel_newZ_norms.append(rel_newZ_norm) try: if adi_dict['verbose']: print ('Number of ADI steps {0} -- \n' + 'Relative norm of the update {1}' ).format(adi_step, rel_newZ_norm) except KeyError: pass # no verbosity specified - nothing is shown return dict(zfac=ufac, adi_rel_newZ_norms=adi_rel_newZ_norms)