def test_rhess_02(): n, d = (50, 3) alpha = randint(1, 10, 2) * .1 beta = randint(1, 10, 2)[0] * .1 man = ComplexPositiveSemidefinite(n, d, alpha=alpha, beta=beta) S = man.rand() # simple function. Distance to a given matrix # || S - A||_F^2 A = hsym(crandn(n, n)) def f(S): diff = (A - S.Y @ S.P @ S.Y.T.conjugate()) return trace(diff @ diff.T.conjugate()) def df(S): return psd_ambient(-4 * A @ S.Y @ S.P, 2 * (S.P - S.Y.T.conjugate() @ A @ S.Y)) def ehess_form(S, xi, eta): return ( trace(-4 * A @ (xi.tY @ S.P + S.Y @ xi.tP) @ eta.tY.T.conjugate()) + 2 * trace( (xi.tP - xi.tY.T.conjugate() @ A @ S.Y - S.Y.T.conjugate() @ A @ xi.tY) @ eta.tP.T.conjugate())).real def ehess_vec(S, xi): return psd_ambient( -4 * A @ (xi.tY @ S.P + S.Y @ xi.tP), 2 * (xi.tP - xi.tY.T.conjugate() @ A @ S.Y - S.Y.T.conjugate() @ A @ xi.tY)) xxi = man.randvec(S) dlt = 1e-8 Snew = psd_point(S.Y + dlt * xxi.tY, S.P + dlt * xxi.tP) d1 = (f(Snew) - f(S)) / dlt d2 = df(S) print(d1 - man.base_inner_ambient(d2, xxi)) eeta = man.randvec(S) d1 = man.base_inner_ambient((df(Snew) - df(S)), eeta) / dlt ehess_val = ehess_form(S, xxi, eeta) dv2 = ehess_vec(S, xxi) print(man.base_inner_ambient(dv2, eeta)) print(d1, ehess_val, d1 - ehess_val) # now check the formula: ehess = xi (eta_func(f)) - <D_xi eta, df(Y)> # promote eta to a vector field. m1 = crandn(n, n) m2 = crandn(d, d) m_p = crandn(d * d, d * d) def eta_field(Sin): return man.proj( S, psd_ambient(m1 @ (Sin.Y - S.Y) @ m2, hsym((m_p @ (Sin.P - S.P).reshape(-1)).reshape( d, d)))) + eeta # xietaf: should go to ehess(xi, eta) + df(Y) @ etafield) xietaf = (man.base_inner_ambient(df(Snew), eta_field(Snew)) - man.base_inner_ambient(df(S), eta_field(S))) / dlt # appy eta_func to f: should go to tr(m1 @ xxi @ m2 @ df(Y).T) Dxietaf = man.base_inner_ambient( (eta_field(Snew) - eta_field(S)), df(S)) / dlt # this is ehess. should be same as d1 or ehess_val print(xietaf - Dxietaf) print(xietaf - Dxietaf - ehess_val) # now check: rhess. Need to make sure xi, eta in the tangent space. # first compare this with numerical differentiation xi1 = man.proj(S, xxi) eta1 = man.proj(S, eeta) egvec = df(S) ehvec = ehess_vec(S, xi1) rhessvec = man.ehess2rhess(S, egvec, ehvec, xi1) # check it numerically: def rgrad_func(Y): return man.proj_g_inv(Y, df(Y)) # val2a, _, _ = calc_covar_numeric_raw(man, W, xi1, df) val2, _, _ = calc_covar_numeric(man, S, xi1, rgrad_func) val2_p = man.proj(S, val2) # print(rhessvec) # print(val2_p) print(man._vec(rhessvec - val2_p)) rhessval = man.inner_product_amb(S, rhessvec, eta1) print(man.inner_product_amb(S, val2, eta1)) print(rhessval) # check symmetric: ehvec_e = ehess_vec(S, eta1) rhessvec_e = man.ehess2rhess(S, egvec, ehvec_e, eta1) rhessval_e = man.inner_product_amb(S, rhessvec_e, xi1) print(rhessval_e) # the above computed inner_prod(Nabla_xi Pi * df, eta) # in the following check. Extend eta1 to eta_proj # (Pi Nabla_hat Pi g_inv df, g eta) # = D_xi (Pi g_inv df, g eta) - (Pi g_inv df g Pi Nabla_hat eta) def eta_proj(S): return man.proj(S, eta_field(S)) print(check_zero(man._vec(eta1 - eta_proj(S)))) e1 = man.inner(S, man.proj_g_inv(S, df(S)), eta_proj(S)) e1a = man.base_inner_ambient(df(S), eta_proj(S)) print(e1, e1a, e1 - e1a) Snew = psd_point(S.Y + dlt * xi1.tY, S.P + dlt * xi1.tP) e2 = man.inner(Snew, man.proj_g_inv(Snew, df(Snew)), eta_proj(Snew)) e2a = man.base_inner_ambient(df(Snew), eta_proj(Snew)) print(e2, e2a, e2 - e2a) first = (e2 - e1) / dlt first1 = (man.base_inner_ambient(df(Snew), eta_proj(Snew)) - man.base_inner_ambient(df(S), eta_proj(S))) / dlt print(first - first1) val3, _, _ = calc_covar_numeric(man, S, xi1, eta_proj) second = man.inner(S, man.proj_g_inv(S, df(S)), man.proj(S, val3)) second2 = man.inner(S, man.proj_g_inv(S, df(S)), val3) print(second, second2, second - second2) print('same as rhess_val %f' % (first - second))
def test_covariance_deriv(): # now test full: # do covariant derivatives # check that it works, preseving everything n, d = (5, 3) alpha = randint(1, 10, 2) * .1 beta = randint(1, 10, 2)[0] * .01 man = ComplexPositiveSemidefinite(n, d, alpha=alpha, beta=beta) S = man.rand() aa = crandn(n * d, n * d) cc = crandn(d * d, d * d) icpt = man._rand_ambient() def omg_func(S): csp = hsym((cc @ S.P.reshape(-1)).reshape(d, d)) return psd_ambient( (aa @ S.Y.reshape(-1) + icpt.tY.reshape(-1)).reshape(n, d), csp + icpt.tP) xi = man.randvec(S) egrad = omg_func(S) ecsp = hsym((cc @ xi.tP.reshape(-1)).reshape(d, d)) ehess = psd_ambient((aa @ xi.tY.reshape(-1)).reshape(n, d), ecsp) val1 = man.ehess2rhess(S, egrad, ehess, xi) def rgrad_func(W): return man.proj_g_inv(W, omg_func(W)) if False: first = ehess a = man.J_g_inv(S, egrad) rgrad = man.proj_g_inv(S, egrad) second = man.D_g(S, xi, man.g_inv(S, egrad)).scalar_mul(-1) aout = man.solve_J_g_inv_Jst(S, a) third = man.proj(S, man.D_g_inv_Jst(S, xi, aout)).scalar_mul(-1) fourth = man.christoffel_form(S, xi, rgrad) val1a1 = man.proj_g_inv(S, first + second + fourth) + third print(check_zero(man._vec(val1 - val1a1))) elif True: d_xi_rgrad = num_deriv_amb(man, S, xi, rgrad_func) rgrad = man.proj_g_inv(S, egrad) fourth = man.christoffel_form(S, xi, rgrad) val1a = man.proj(S, d_xi_rgrad) + man.proj_g_inv(S, fourth) print(check_zero(man._vec(val1 - val1a))) # nabla_v_xi, dxi, cxxi val2a, _, _ = calc_covar_numeric(man, S, xi, omg_func) val2, _, _ = calc_covar_numeric(man, S, xi, rgrad_func) # val2_p = project(prj, val2) val2_p = man.proj(S, val2) # print(val1) # print(val2_p) print(check_zero(man._vec(val1) - man._vec(val2_p))) if True: H = xi valrangeA_ = ehess + man.g(S, man.D_proj( S, H, man.g_inv(S, egrad))) - man.D_g( S, H, man.g_inv(S, egrad)) +\ man.christoffel_form(S, H, man.proj_g_inv(S, egrad)) valrangeB = man.proj_g_inv(S, valrangeA_) valrange = man.ehess2rhess_alt(S, egrad, ehess, xi) print(check_zero(man._vec(valrange) - man._vec(val2_p))) print(check_zero(man._vec(valrange) - man._vec(val1))) print(check_zero(man._vec(valrange) - man._vec(valrangeB)))