def test_chris_vectorfields(): # now test that it works on embedded metrics # we test that D_xi (eta g eta) = 2(eta g nabla_xi eta) n, d = (5, 3) alpha = randint(1, 10, 2) * .1 beta = randint(1, 10, 1)[0] * .1 man = RealPositiveSemidefinite(n, d, alpha=alpha, beta=beta) S0 = man.rand() aa = randn(n * d, n * d) intc = randn(n * d) cc = randn(d * d, d * d) p_intc = sym(randn(d, d)) inct_xi = man._rand_ambient() aa_xi = randn(n * d, n * d) cc_xi = randn(d * d, d * d) def v_func(S): # a function from the manifold # to ambient csp = sym((cc @ (S.P - S0.P).reshape(-1)).reshape(d, d)) return man.proj( S, psd_ambient((aa @ (S.Y - S0.Y).reshape(-1) + intc).reshape(n, d), csp + p_intc)) SS = psd_point(S0.Y, S0.P) xi = man.proj(SS, inct_xi) nabla_xi_v, dv, cxv = calc_covar_numeric(man, SS, xi, v_func) def xi_func(S): csp_xi = sym((cc_xi @ (S.P - S0.P).reshape(-1)).reshape(d, d)) xi_amb = psd_ambient((aa_xi @ (S.Y - S0.Y).reshape(-1) + inct_xi.tY.reshape(-1)).reshape(n, d), csp_xi + inct_xi.tP) return man.proj(S, xi_amb) vv = v_func(SS) nabla_v_xi, dxi, cxxi = calc_covar_numeric(man, SS, vv, xi_func) diff = nabla_xi_v - nabla_v_xi print(diff.tY, diff.tP) # now do Lie bracket: dlt = 1e-7 SnewXi = psd_point(SS.Y + dlt * xi.tY, SS.P + dlt * xi.tP) Snewvv = psd_point(SS.Y + dlt * vv.tY, SS.P + dlt * vv.tP) vnewxi = v_func(SnewXi) xnewv = xi_func(Snewvv) dxiv = (vnewxi - vv).scalar_mul(1 / dlt) dvxi = (xnewv - xi).scalar_mul(1 / dlt) diff2 = man.proj(SS, dxiv - dvxi) print(check_zero(man._vec(diff) - man._vec(diff2)))
def calc_covar_numeric(man, S, xi, v_func): """ compute nabla on E dont do the metric lower index. So basically Nabla (Pi e). Thus, if we want to do Nabla Pi g_inv df We need to send g_inv df """ def vv_func(W): return man.proj(W, v_func(W)) vv = vv_func(S) dlt = 1e-7 Snew = psd_point(S.Y + dlt * xi.tY, S.P + dlt * xi.tP) vnew = vv_func(Snew) val = man.inner_product_amb(S, vv) valnew = man.inner_product_amb(Snew, vnew) d1 = (valnew - val) / dlt dv = (vnew - vv).scalar_mul(1 / dlt) cx = man.christoffel_form(S, xi, vv) nabla_xi_v_up = dv + man.g_inv(S, cx) nabla_xi_v = man.proj(S, nabla_xi_v_up) if False: d2 = man.inner_product_amb(S, vv, nabla_xi_v) d2up = man.inner_product_amb(S, vv, nabla_xi_v_up) print(d1) print(2 * d2up) print(2 * d2) return nabla_xi_v, dv, cx
def test_geodesics(): from scipy.linalg import expm alpha = np.random.randint(1, 10, (2)) * .1 beta = alpha[1] * .1 m, d = (5, 3) man = RealPositiveSemidefinite(m, d, alpha=alpha, beta=beta) X = man.rand() alf = alpha[1] / alpha[0] def calc_gamma(man, X, xi, eta): g_inv_Jst_solve_J_g_in_Jst_DJ = man.g_inv( X, man.Jst(X, man.solve_J_g_inv_Jst(X, man.D_J(X, xi, eta)))) proj_christoffel = man.proj_g_inv(X, man.christoffel_form(X, xi, eta)) return g_inv_Jst_solve_J_g_in_Jst_DJ + proj_christoffel eta = man.randvec(X) g1 = calc_gamma(man, X, eta, eta) g2 = man.christoffel_gamma(X, eta, eta) print(man._vec(g1 - g2)) egrad = man._rand_ambient() print(man.base_inner_ambient(g1, egrad)) print(man.rhess02_alt(X, eta, eta, egrad, 0)) print(man.rhess02(X, eta, eta, egrad, man.zerovec(X))) # second solution: A = X.Y.T @ eta.tY t = 2 K = eta.tY - X.Y @ (X.Y.T @ eta.tY) Yp, R = np.linalg.qr(K) x_mat = np.bmat([[2 * alf * A, -R.T], [R, zeros((d, d))]]) Yt = np.bmat([X.Y, Yp]) @ expm(t*x_mat)[:, :d] @ \ expm(t*(1-2*alf)*A) x_d_mat = x_mat[:, :d].copy() x_d_mat[:d, :] += (1 - 2 * alf) * A Ydt = np.bmat([X.Y, Yp]) @ expm(t*x_mat) @ x_d_mat @\ expm(t*(1-2*alf)*A) x_dd_mat = x_mat @ x_d_mat + x_d_mat @ ((1 - 2 * alf) * A) Yddt = np.bmat([X.Y, Yp]) @ expm(t*x_mat) @ x_dd_mat @\ expm(t*(1-2*alf)*A) sqrtP = X.evec @ np.diag(np.sqrt(X.evl)) @ X.evec.T isqrtP = X.evec @ np.diag(1 / np.sqrt(X.evl)) @ X.evec.T Pinn = t * isqrtP @ eta.tP @ isqrtP ePinn = expm(Pinn) Pt = sqrtP @ ePinn @ sqrtP Pdt = eta.tP @ isqrtP @ ePinn @ sqrtP Pddt = eta.tP @ isqrtP @ ePinn @ isqrtP @ eta.tP Xt = psd_point(np.array(Yt), np.array(Pt)) Xdt = psd_ambient(np.array(Ydt), np.array(Pdt)) Xddt = psd_ambient(np.array(Yddt), np.array(Pddt)) gcheck = Xddt + calc_gamma(man, Xt, Xdt, Xdt) print(man._vec(gcheck)) Xt1 = man.exp(X, t * eta) print((Xt1.Y - Xt.Y)) print((Xt1.P - Xt.P))
def test_christ_flat(): """now test that christofel preserve metrics: on the flat space d_xi <v M v> = 2 <v M nabla_xi v> v = proj(W) @ (aa W + b) """ alpha = randint(1, 10, 2) * .1 beta = randint(1, 10, 2)[0] * .1 n = 5 d = 3 man = RealPositiveSemidefinite(n, d, alpha=alpha, beta=beta) S = man.rand() xi = man.randvec(S) xi = man.randvec(S) aa = randn(n * d, n * d) bb = randn(n * d) cc = randn(d * d, d * d) dd = sym(randn(d, d)) def v_func_flat(S): # a function from the manifold # to ambient csp = sym((cc @ S.P.reshape(-1)).reshape(d, d)) return psd_ambient((aa @ S.Y.reshape(-1) + bb).reshape(n, d), csp + dd) vv = v_func_flat(S) dlt = 1e-7 Snew = psd_point(S.Y + dlt * xi.tY, S.P + dlt * xi.tP) vnew = v_func_flat(Snew) val = man.inner_product_amb(S, vv) valnew = man.inner_product_amb(Snew, vnew) d1 = (valnew - val) / dlt dv = (vnew - vv).scalar_mul(1 / dlt) nabla_xi_v = dv + man.g_inv(S, man.christoffel_form(S, xi, vv)) nabla_xi_va = dv + man.g_inv( S, super(RealPositiveSemidefinite, man).christoffel_form(S, xi, vv)) print(check_zero(man._vec(nabla_xi_v) - man._vec(nabla_xi_va))) d2 = man.inner(S, vv, nabla_xi_v) print(d1) print(2 * d2)
def test_rhess_02(): n, d = (5, 3) alpha = randint(1, 10, 2) * .1 beta = randint(1, 10, 2)[0] * .1 man = RealPositiveSemidefinite(n, d, alpha=alpha, beta=beta) S = man.rand() # simple function. Distance to a given matrix # || S - A||_F^2 A = sym(randn(n, n)) def f(S): diff = (A - S.Y @ S.P @ S.Y.T) return trace(diff @ diff.T) def df(S): return psd_ambient(-4 * A @ S.Y @ S.P, 2 * (S.P - S.Y.T @ A @ S.Y)) def ehess_form(S, xi, eta): return trace(-4*A @ (xi.tY @ S.P + S.Y @ xi.tP) @ eta.tY.T) +\ 2*trace((xi.tP - xi.tY.T@[email protected] - S.Y.T@[email protected]) @ eta.tP.T) def ehess_vec(S, xi): return psd_ambient(-4 * A @ (xi.tY @ S.P + S.Y @ xi.tP), 2 * (xi.tP - xi.tY.T @ A @ S.Y - S.Y.T @ 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 = randn(n, n) m2 = randn(d, d) m_p = randn(d * d, d * d) def eta_field(Sin): return man.proj( S, psd_ambient(m1 @ (Sin.Y - S.Y) @ m2, sym((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 num_deriv_amb(man, S, xi, func, dlt=1e-7): Snew = psd_point(S.Y + dlt * xi.tY, S.P + dlt * xi.tP) return (func(Snew) - func(S)).scalar_mul(1 / dlt)
def test_all_projections(): alpha = randint(1, 10, 2) * .1 beta = randint(1, 10, 1)[0] * .02 n = 5 d = 3 man = RealPositiveSemidefinite(n, d, alpha=alpha, beta=beta) print(man) S = man.rand() test_inner(man, S) test_J(man, S) # now check metric, Jst etc # check Jst: vectorize the operator J then compare Jst with jmat.T jmat = make_j_mat(man, S) test_Jst(man, S, jmat) ginv_mat = make_g_inv_mat(man, S) # test g_inv_Jst for ii in range(10): a = man._rand_range_J() avec = man._vec_range_J(a) jtout = ginv_mat @ jmat.T @ avec jtout2 = man._vec(man.g_inv_Jst(S, a)) diff = check_zero(jtout - jtout2) print(diff) # test projection test_projection(man, S) # now diff projection for i in range(1): e = man._rand_ambient() S1 = man.rand() xi = man.randvec(S1) dlt = 1e-7 S2 = psd_point(S1.Y + dlt * xi.tY, S1.P + dlt * xi.tP) # S = psd_point(S1.Y, S1.P) """ U = e D = man._calc_D(S1, U) print((man.alpha[1] - 2*man.beta)*D + 2*man.beta*(sym(S.P@[email protected]))) print(sym(U.tP + [email protected]@S.P - [email protected]@U.tY)) Dnew = man._calc_D(S2, U) print((Dnew - D)/dlt) ddin = xi.tY.T @ U.tY @ S.P - S.P @ xi.tY.T @ U.tY + \ S.Y.T @ U.tY @ xi.tP - xi.tP @ S.Y.T @ U.tY - man.beta * ( xi.tP @ D @ S.Pinv + S.Pinv @ D @ xi.tP - S.P @ D @ S.Pinv @ xi.tP @ S.Pinv - S.Pinv @ xi.tP @ S.Pinv @ D @ S.P) DD = _extended_lyapunov( man.alpha[1], man.beta, S.P, sym(ddin), S.evl, S.evec) """ d1P = (man.proj(S2, e).tP - man.proj(S1, e).tP) / dlt d1Y = (man.proj(S2, e).tY - man.proj(S1, e).tY) / dlt d2 = man.D_proj(S1, xi, e) print(check_zero(d1P - d2.tP) + check_zero(d1Y - d2.tY)) for i in range(10): a = man._rand_range_J() eta = man._rand_ambient() print(man.base_inner_ambient(eta, man.Jst(S, a))) print( trace((eta.tP.T - eta.tP) @ a['P'] + (man.alpha[1] * eta.tY.T @ S.Y + man.beta * (S.Pinv @ eta.tP.T - eta.tP.T @ S.Pinv)) @ a['YP'])) print( trace(2 * eta.tP.T @ a['P']) + trace((man.alpha[1] * eta.tY.T @ S.Y + man.beta * (S.Pinv @ eta.tP.T - eta.tP.T @ S.Pinv)) @ a['YP'])) print( trace(eta.tP.T @ (2 * a['P'] + man.beta * (a['YP'] @ S.Pinv - S.Pinv @ a['YP']))) + trace(eta.tY.T @ (man.alpha[1] * S.Y @ a['YP']))) print(man.base_inner_E_J(man.J(S, eta), a)) print( trace((eta.tP - eta.tP.T).T @ a['P'] + (man.alpha[1] * S.Y.T @ eta.tY + man.beta * (eta.tP @ S.Pinv - S.Pinv @ eta.tP)).T @ a['YP'])) for i in range(10): a = man._rand_range_J() beta = man.beta alf = man.alpha anew1 = man.J(S, man.g_inv_Jst(S, a)) anew = {} saYP = a['YP'] + a['YP'].T anew['P'] = 4 / beta * S.P @ a['P'] @ S.P + S.P @ saYP - saYP @ S.P anew['YP'] = alf[1] * a['YP'] + beta * ( ((2 / man.beta) * S.P @ a['P'] @ S.P + S.P @ a['YP'] - a['YP'] @ S.P) @ S.Pinv - S.Pinv @ ( (2 / man.beta) * S.P @ a['P'] @ S.P + S.P @ a['YP'] - a['YP'] @ S.P)) anew['YP'] = alf[1] * a['YP'] + ( (2 * S.P @ a['P'] + beta * S.P @ a['YP'] @ S.Pinv - beta * a['YP']) - (2 * a['P'] @ S.P + beta * a['YP'] - beta * S.Pinv @ a['YP'] @ S.P)) anew['YP'] = (alf[1] - 2 * beta) * a['YP'] + ( (2 * S.P @ a['P'] + beta * S.P @ a['YP'] @ S.Pinv) - (2 * a['P'] @ S.P - beta * S.Pinv @ a['YP'] @ S.P)) anew['YP'] = (alf[1] - 2 * beta) * a['YP'] + ( (2 * S.P @ a['P'] - 2 * a['P'] @ S.P + beta * S.P @ a['YP'] @ S.Pinv + beta * S.Pinv @ a['YP'] @ S.P)) print(check_zero(man._vec_range_J(anew1) - man._vec_range_J(anew))) for i in range(10): a = man._rand_range_J() b1 = man.J(S, man.g_inv_Jst(S, a)) b2 = man.J_g_inv_Jst(S, a) print(check_zero(man._vec_range_J(b1) - man._vec_range_J(b2))) a1 = man.solve_J_g_inv_Jst(S, b1) print(check_zero(man._vec_range_J(a) - man._vec_range_J(a1))) for ii in range(10): E = man._rand_ambient() a2 = man.J_g_inv(S, E) a1 = man.J(S, man.g_inv(S, E)) print(check_zero(man._vec_range_J(a1) - man._vec_range_J(a2))) for i in range(20): Uran = man._rand_ambient() Upr = man.proj(S, man.g_inv(S, Uran)) Upr2 = man.proj_g_inv(S, Uran) print(check_zero(man._vec(Upr) - man._vec(Upr2))) for ii in range(10): a = man._rand_range_J() xi = man.randvec(S) jtout2 = man.Jst(S, a) dlt = 1e-7 Snew = psd_point(S.Y + dlt * xi.tY, S.P + dlt * xi.tP) jtout2a = man.Jst(Snew, a) d1 = (jtout2a - jtout2).scalar_mul(1 / dlt) d2 = man.D_Jst(S, xi, a) print(check_zero(man._vec(d2) - man._vec(d1))) for ii in range(10): S1 = man.rand() eta = man._rand_ambient() xi = man.randvec(S1) a1 = man.J(S1, eta) dlt = 1e-8 Snew = psd_point(S1.Y + dlt * xi.tY, S1.P + dlt * xi.tP) a2 = man.J(Snew, eta) d1 = { 'P': (a2['P'] - a1['P']) / dlt, 'YP': (a2['YP'] - a1['YP']) / dlt } d2 = man.D_J(S1, xi, eta) print(check_zero(man._vec_range_J(d2) - man._vec_range_J(d1))) # derives metrics for ii in range(10): S1 = man.rand() xi = man.randvec(S1) omg1 = man._rand_ambient() omg2 = man._rand_ambient() dlt = 1e-7 S2 = psd_point(S1.Y + dlt * xi.tY, S1.P + dlt * xi.tP) p1 = man.inner(S1, omg1, omg2) p2 = man.inner(S2, omg1, omg2) der1 = (p2 - p1) / dlt der2 = man.base_inner_ambient(man.D_g(S1, xi, omg2), omg1) print(der1 - der2) # cross term for christofel for i in range(10): S1 = man.rand() xi = man.randvec(S1) eta1 = man.randvec(S1) eta2 = man.randvec(S1) dr1 = man.D_g(S1, xi, eta1) x12 = man.contract_D_g(S1, eta1, eta2) p1 = man.base_inner_ambient(dr1, eta2) p2 = man.base_inner_ambient(x12, xi) print(p1, p2, p1 - p2) # now test christofel: # two things: symmetric on vector fields # and christofel relation # in the case metric for i in range(10): S1 = man.rand() xi = man.randvec(S1) eta1 = man.randvec(S1) eta2 = man.randvec(S1) p1 = man.proj_g_inv(S1, man.christoffel_form(S1, xi, eta1)) p2 = man.proj_g_inv(S1, man.christoffel_form(S1, eta1, xi)) print(check_zero(man._vec(p1) - man._vec(p2))) v1 = man.base_inner_ambient(man.christoffel_form(S1, eta1, eta2), xi) v2 = man.base_inner_ambient(man.D_g(S1, eta1, eta2), xi) v3 = man.base_inner_ambient(man.D_g(S1, eta2, eta1), xi) v4 = man.base_inner_ambient(man.D_g(S1, xi, eta1), eta2) print(v1, 0.5 * (v2 + v3 - v4), v1 - 0.5 * (v2 + v3 - v4))