Exemple #1
0
def optim_test():
    n, d = (1000, 50)
    # n, d = (10, 3)
    # simple function. Distance to a given matrix
    # || S - A||_F^2
    Y0, _ = np.linalg.qr(crandn(n, d))
    P0 = np.diag(randint(1, 1000, d) * .001)
    A00 = Y0 @ P0 @ Y0.T.conjugate()
    A0 = hsym(A00)
    A = (hsym(crandn(n, n)) * 1e-2 + A0)

    alpha = np.array([1, 1])
    print("alpha %s" % str(alpha))

    beta = alpha[1] * .1
    man = ComplexPositiveSemidefinite(n, d, alpha=alpha, beta=beta)
    XInit = man.rand()
    opt_pre = solve_dist_with_man(man, A, X0=XInit, maxiter=20)

    beta = alpha[1] * 1
    man = ComplexPositiveSemidefinite(n, d, alpha=alpha, beta=beta)
    opt_mid = solve_dist_with_man(man, A, X0=opt_pre, maxiter=20)
    # opt_mid = opt_pre

    beta = alpha[1] * 30
    man = ComplexPositiveSemidefinite(n, d, alpha=alpha, beta=beta)
    opt = solve_dist_with_man(man, A, X0=opt_mid, maxiter=500)
    opt_mat = opt.Y @ opt.P @ opt.Y.T.conjugate()
    if False:
        print(A0)
        print(opt_mat)
    print(np.max(np.abs(A0 - opt_mat)))
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
    gamma = randint(1, 10, 2) * .1
    beta = randint(1, 10, 2)[0] * .1

    m = 4
    n = 5
    p = 3
    man = ComplexFixedRank(m, n, p, alpha=alpha, beta=beta, gamma=gamma)
    
    S = man.rand()
    
    xi = man.randvec(S)
    aaU = crandn(m*p, m*p)
    bbU = crandn(m*p)

    aaV = crandn(n*p, n*p)
    bbV = crandn(n*p)
    
    cc = crandn(p*p, p*p)
    dd = hsym(crandn(p, p))
        
    def v_func_flat(S):
        # a function from the manifold
        # to ambient
        csp = hsym((cc @ S.P.reshape(-1)).reshape(p, p))
        
        return fr_ambient(
            (aaU @ S.U.reshape(-1) + bbU).reshape(m, p),
            (aaV @ S.V.reshape(-1) + bbV).reshape(n, p),
            csp + dd)

    vv = v_func_flat(S)  # vv is not horizontal
    dlt = 1e-7
    Snew = fr_point(
        S.U + dlt * xi.tU,
        S.V + dlt * xi.tV,
        S.P + dlt * xi.tP)
    vnew = v_func_flat(Snew)

    val = man.inner(S, vv)
    valnew = man.inner(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))
    # not equal bc vv is not horizontal:
    nabla_xi_va = dv + man.g_inv(
        S, super(ComplexFixedRank, 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 get_D2(omg):
     UTomg = X.U.T.conj()@omg.tU
     VTomg = X.V.T.conj()@omg.tV
     Piv = X.Pinv
     D2 = hsym([email protected]@X.Pinv + 1/(al[1]+gm[1])*(
         al[1]*(Piv@UTomg - UTomg@Piv) +
         gm[1]*(Piv@VTomg - VTomg@Piv)))
     return D2
    def NTgN_opt(X, B, C, D):
        Piv = X.Pinv
        Dp, Dm = hsym(D), ahsym(D)
        Dp_ = (1/bt-2/(al[1]+gm[1]))*Piv@Dp@Piv + 1/(al[1]+gm[1])*(
            [email protected]@[email protected]@X.Pinv)
        Dm_ = al[1]*gm[1]*(al[1]+gm[1])*Dm

        return al[0]*B, gm[0]*C, Dp_ + Dm_
 def v_func_flat(S):
     # a function from the manifold
     # to ambient
     csp = hsym((cc @ S.P.reshape(-1)).reshape(p, p))
     
     return fr_ambient(
         (aaU @ S.U.reshape(-1) + bbU).reshape(m, p),
         (aaV @ S.V.reshape(-1) + bbV).reshape(n, p),
         csp + dd)
 def xi_func(S):
     csp_xi = hsym((cc_xi @ (S.P-S0.P).reshape(-1)).reshape(p, p))
     xi_amb = fr_ambient(
         (aa_xiU @ (S.U-S0.U).reshape(-1) +
          inct_xi.tU.reshape(-1)).reshape(m, p),
         (aa_xiV @ (S.V-S0.V).reshape(-1) +
          inct_xi.tV.reshape(-1)).reshape(n, p),
         csp_xi + inct_xi.tP)
     return man.proj(S, xi_amb)
 def v_func(S):
     # a function from the manifold
     # to ambient
     csp = hsym((cc @ (S.P-S0.P).reshape(-1)).reshape(p, p))
     
     return man.proj(S, fr_ambient(
         (aaU @ (S.U-S0.U).reshape(-1) + intcU).reshape(m, p),
         (aaV @ (S.V-S0.V).reshape(-1) + intcV).reshape(n, p),
         csp + p_intc))
Exemple #8
0
    def v_func(S):
        # a function from the manifold
        # to ambient
        csp = hsym((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))
Exemple #9
0
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 = (20, 3)
    alpha = randint(1, 10, 2) * .1
    beta = randint(1, 10, 1)[0] * .1
    man = ComplexPositiveSemidefinite(n, d, alpha=alpha, beta=beta)

    S0 = man.rand()
    aa = crandn(n * d, n * d)
    intc = crandn(n * d)
    cc = crandn(d * d, d * d)
    p_intc = hsym(crandn(d, d))

    inct_xi = man._rand_ambient()
    aa_xi = crandn(n * d, n * d)
    cc_xi = crandn(d * d, d * d)

    def v_func(S):
        # a function from the manifold
        # to ambient
        csp = hsym((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 = hsym((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 N(man, X, B, C, D):
    al, bt, gm = (man.alpha, man.beta, man.gamma)
    U, V, Piv = (X.U, X.V, X.Pinv)
    Dm = ahsym(D)
    Dp = hsym(D)
    bkPivDp = Piv @ Dp - Dp @ Piv
    U0 = null_space(X._U.T.conj())
    V0 = null_space(X._V.T.conj())
    U0B = U0 @ B
    V0C = V0 @ C
    return fr_ambient(
        U @ (-gm[1]*Dm + 1/(al[1]+gm[1])*bkPivDp)+U0B,
        V @(al[1]*Dm + 1/(al[1]+gm[1])*bkPivDp)+V0C,
        1/bt*Dp)
Exemple #11
0
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 = 20
    d = 3
    man = ComplexPositiveSemidefinite(n, d, alpha=alpha, beta=beta)
    S = man.rand()

    xi = man.randvec(S)
    xi = man.randvec(S)
    aa = crandn(n * d, n * d)
    bb = crandn(n * d)
    cc = crandn(d * d, d * d)
    dd = hsym(crandn(d, d))

    def v_func_flat(S):
        # a function from the manifold
        # to ambient
        csp = hsym((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(ComplexPositiveSemidefinite, 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)
Exemple #12
0
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)))
Exemple #13
0
 def xi_func(S):
     csp_xi = hsym((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)
Exemple #14
0
    def v_func_flat(S):
        # a function from the manifold
        # to ambient
        csp = hsym((cc @ S.P.reshape(-1)).reshape(d, d))

        return psd_ambient((aa @ S.Y.reshape(-1) + bb).reshape(n, d), csp + dd)
 def eta_field(Sin):
     return man.proj(S, fr_ambient(
         mU1 @ (Sin.U - S.U) @ m2,
         mV1 @ (Sin.V - S.V) @ m2,
         hsym((m_p @ (Sin.P - S.P).reshape(-1)).reshape(p, p)))) + eeta
 def solveNTgN(X, Bo, Co, Do):
     Dp, Dm = hsym(Do), ahsym(Do)
     Dm_ = 1/(al[1]*gm[1]*(al[1]+gm[1]))*Dm
     Dp_ = complex_extended_lyapunov(1/bt, 1/(al[1]+gm[1]), X.P, X.P@[email protected])
     
     return 1/al[0]*Bo, 1/gm[0]*Co, Dp_ + Dm_
Exemple #17
0
 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
Exemple #18
0
 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)
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)
    alpha = randint(1, 10, 2) * .1
    gamma = randint(1, 10, 2) * .1
    beta = randint(1, 10, 2)[0] * .1

    m = 4
    n = 5
    p = 3
    man = ComplexFixedRank(m, n, p, alpha=alpha, beta=beta, gamma=gamma)

    S0 = man.rand()
    aaU = crandn(m*p, m*p)
    intcU = crandn(m*p)
    aaV = crandn(n*p, n*p)
    intcV = crandn(n*p)
    
    cc = crandn(p*p, p*p)
    p_intc = hsym(crandn(p, p))

    inct_xi = man._rand_ambient()
    aa_xiU = crandn(m*p, m*p)
    aa_xiV = crandn(n*p, n*p)
    cc_xi = crandn(p*p, p*p)
    
    def v_func(S):
        # a function from the manifold
        # to ambient
        csp = hsym((cc @ (S.P-S0.P).reshape(-1)).reshape(p, p))
        
        return man.proj(S, fr_ambient(
            (aaU @ (S.U-S0.U).reshape(-1) + intcU).reshape(m, p),
            (aaV @ (S.V-S0.V).reshape(-1) + intcV).reshape(n, p),
            csp + p_intc))

    SS = fr_point(S0.U, S0.V, 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 = hsym((cc_xi @ (S.P-S0.P).reshape(-1)).reshape(p, p))
        xi_amb = fr_ambient(
            (aa_xiU @ (S.U-S0.U).reshape(-1) +
             inct_xi.tU.reshape(-1)).reshape(m, p),
            (aa_xiV @ (S.V-S0.V).reshape(-1) +
             inct_xi.tV.reshape(-1)).reshape(n, p),
            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.tU, diff.tV, diff.tP)
    # now do Lie bracket:
    dlt = 1e-7
    SnewXi = fr_point(SS.U+dlt*xi.tU,
                      SS.V+dlt*xi.tV,
                      SS.P+dlt*xi.tP)
    Snewvv = fr_point(SS.U+dlt*vv.tU,
                      SS.V+dlt*vv.tV,
                      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)))
Exemple #20
0
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
    alpha = randint(1, 10, 2) * .1
    gamma = randint(1, 10, 2) * .1
    beta = randint(1, 10, 2)[0] * .1

    m = 4
    n = 5
    p = 3
    man = ComplexFixedRank(m, n, p, alpha=alpha, beta=beta, gamma=gamma)
    
    S = man.rand()
    
    aaU = crandn(m*p, m*p)
    aaV = crandn(n*p, n*p)
    cc = crandn(p*p, p*p)
    icpt = man._rand_ambient()

    def omg_func(S):
        csp = hsym((cc @ S.P.reshape(-1)).reshape(p, p))
        return fr_ambient(
            (aaU @ S.U.reshape(-1) + icpt.tU.reshape(-1)).reshape(m, p),
            (aaV @ S.V.reshape(-1) + icpt.tV.reshape(-1)).reshape(n, p),
            csp + icpt.tP)

    xi = man.randvec(S)
    egrad = omg_func(S)
    ecsp = hsym((cc @ xi.tP.reshape(-1)).reshape(p, p))
    ehess = fr_ambient(
        (aaU @ xi.tU.reshape(-1)).reshape(m, p),
        (aaV @ xi.tV.reshape(-1)).reshape(n, p),
        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(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)))
 def omg_func(S):
     csp = hsym((cc @ S.P.reshape(-1)).reshape(p, p))
     return fr_ambient(
         (aaU @ S.U.reshape(-1) + icpt.tU.reshape(-1)).reshape(m, p),
         (aaV @ S.V.reshape(-1) + icpt.tV.reshape(-1)).reshape(n, p),
         csp + icpt.tP)
def test_J(man, X):
    from scipy.linalg import null_space
    al = man.alpha
    bt = man.beta
    gm = man.gamma
    p = man.p
    # U, V, P, Piv = (X.U, X.V, X.P, X.Pinv)
    
    jjmat = np.zeros((8*p*p, man.tdim))
    # this map is not full onto - but just check tangent maps to zero
    for i in range(man.tdim):
        Ux = zeros(man.tdim)
        Ux[i] = 1
        omg = man._unvec(Ux)
        jjmat[:, i] = np.concatenate(
            [cvec(stU(X, omg)),
             cvec(stV(X, omg)),
             cvec(symP(X, omg)),
             cvec(Hz(man, X, omg))])

    # nsp = null_space(jjmat)
    # prj = nsp @ la.solve(nsp.T.conj() @ nsp, nsp.T.conj())
    
    omg = man._rand_ambient()
    eta = man.proj(X, omg)

    def rand_vertical():
        oo = crandn(man.p, man.p)
        oo = oo - oo.T.conj()
        return fr_ambient(
            X.U @ oo,
            X.V @ oo,
            -oo @ X.P + X.P @oo)

    vv = rand_vertical()
    print(man.inner(X, vv, eta))
    nmat = make_N_mat(man, X)
    gmat = make_g_mat(man, X)
    NTgN = nmat.T @ gmat @ nmat
    bcd = nmat.T @ gmat @ man._vec(omg)
    m, n, p = (man.m, man.n, man.p)
    B = cunvec(bcd[:2*(m-p)*p], (m-p, p))
    C = cunvec(bcd[2*(m-p)*p:2*(m+n-2*p)*p], (n-p, p))
    D = cunvec(bcd[2*(m+n-2*p)*p:], (p, p))
    Dp = hsym(D)
    Dm = ahsym(D)
    Dm2 = al[1]*gm[1]*ahsym(X.V.T.conj()@omg.tV - X.U.T.conj()@omg.tU)
    pprint(Dm - Dm2)
    U0 = null_space(X._U.T.conj())
    V0 = null_space(X._V.T.conj())
    B2 = al[0]*U0.T.conj()@omg.tU
    pprint(B-B2)
    C2 = gm[0]*V0.T.conj()@omg.tV
    pprint(C-C2)
    Dmsolve = Dm2/(al[1]+gm[1])/al[1]/gm[1]
    pprint(Dmsolve - (1/(al[1]+gm[1]))*(
        ahsym(X.V.T.conj()@omg.tV - X.U.T.conj()@omg.tU)))
    Dpsolve = complex_extended_lyapunov(1/bt, 1/(al[1]+gm[1]), X.P, X.P@[email protected])
    Drecv = (1/bt-2/(al[1]+gm[1]))*X.Pinv@[email protected] + 1/(al[1]+gm[1])*(
        [email protected]@[email protected]@X.Pinv)
    pprint(Drecv - Dp)
    
    def get_D2(omg):
        UTomg = X.U.T.conj()@omg.tU
        VTomg = X.V.T.conj()@omg.tV
        Piv = X.Pinv
        D2 = hsym([email protected]@X.Pinv + 1/(al[1]+gm[1])*(
            al[1]*(Piv@UTomg - UTomg@Piv) +
            gm[1]*(Piv@VTomg - VTomg@Piv)))
        return D2
                                                
    Dp2 = get_D2(omg)
    print(check_zero(Dp - Dp2))

    def NTgN_opt(X, B, C, D):
        Piv = X.Pinv
        Dp, Dm = hsym(D), ahsym(D)
        Dp_ = (1/bt-2/(al[1]+gm[1]))*Piv@Dp@Piv + 1/(al[1]+gm[1])*(
            [email protected]@[email protected]@X.Pinv)
        Dm_ = al[1]*gm[1]*(al[1]+gm[1])*Dm

        return al[0]*B, gm[0]*C, Dp_ + Dm_

    def solveNTgN(X, Bo, Co, Do):
        Dp, Dm = hsym(Do), ahsym(Do)
        Dm_ = 1/(al[1]*gm[1]*(al[1]+gm[1]))*Dm
        Dp_ = complex_extended_lyapunov(1/bt, 1/(al[1]+gm[1]), X.P, X.P@[email protected])
        
        return 1/al[0]*Bo, 1/gm[0]*Co, Dp_ + Dm_

    def testNTgN(man, X):
        m, n, p = (man.m, man.n, man.p)
        B0 = crandn(m-p, p)
        C0 = crandn(n-p, p)
        D0 = crandn(p, p)
        out1 = NTgN @ np.concatenate(
            [cvec(B0), cvec(C0), cvec(D0)])
        out2a = NTgN_opt(X, B0, C0, D0)
        out2 = np.concatenate(
            [cvec(out2a[0]), cvec(out2a[1]), cvec(out2a[2])])
        print(check_zero(out1-out2))
        out2b = solveNTgN(X, *out2a)
        print(check_zero(out2b[2]-D0))
        print(check_zero(out2b[1]-C0))
        print(check_zero(out2b[0]-B0))
    
    Bs, Cs, Ds = solveNTgN(X, B, C, D)
    # the formulas Using the orthogonal complements of U and V
    
    # Dsm = ahsym(Ds)
    # Dsp = hsym(Ds)
    Bf = U0.T.conj() @ omg.tU
    Cf = V0.T.conj() @ omg.tV
    print(check_zero(Bf-Bs))
    print(check_zero(Cf-Cs))
    Dfm = 1/(al[1]+gm[1])*ahsym(X.V.T.conj()@omg.tV - X.U.T.conj()@omg.tU)
    UTomg = X.U.T.conj()@omg.tU
    VTomg = X.V.T.conj()@omg.tV
    Dfp = complex_extended_lyapunov(
        1/bt, 1/(al[1]+gm[1]), X.P,
        hsym(omg.tP + 1/(al[1]+gm[1])*(
            al[1]*([email protected] - X.P@UTomg) +
            gm[1]*([email protected] - X.P@VTomg))), X.evl, X.evec)
    ee1 = N(man, X, Bf, Cf, Dfp+Dfm)
    print(check_zero(Ds - Dfm - Dfp))
    print(check_zero(man._vec(ee1-eta)))