Пример #1
0
def _test_eigen_tensor(k, m, max_err, max_itr, n_test):
    def sphere_func(x):
        return np.dot(x.T, x) - 1

    def sphere_jacobian(x):
        return 2 * x.reshape(1, -1)

    def sphere_retraction(x, u):
        return (x + u) / np.linalg.norm(x + u)

    sphere = base_constraints(shape_in=(k, ),
                              shape_constraint=(1, ),
                              equality=sphere_func)

    sphere.set_analytics(J_C=sphere_jacobian, retraction=sphere_retraction)

    A = utils.generate_symmetric_tensor(k, m)
    e = eigen_tensor_lagrange(A)
    e.constraints = sphere

    o_ncm_cnt = np.zeros(n_test, dtype=int)
    schur_cnt = np.zeros(n_test, dtype=int)
    ray_cnt = np.zeros(n_test, dtype=int)
    schur_cheb_cnt = np.zeros(n_test, dtype=int)

    o_ncm_err = np.zeros(n_test)
    schur_err = np.zeros(n_test)
    ray_err = np.zeros(n_test)
    schur_cheb_err = np.zeros(n_test)

    o_ncm_lbd = np.zeros(n_test)
    schur_lbd = np.zeros(n_test)
    ray_lbd = np.zeros(n_test)
    schur_cheb_lbd = np.zeros(n_test)

    o_ncm_time = np.zeros(n_test)
    schur_time = np.zeros(n_test)
    ray_time = np.zeros(n_test)
    schur_cheb_time = np.zeros(n_test)

    for jj in range(n_test):
        x0 = np.random.randn(k)
        x0 = x0 / np.linalg.norm(x0)

        # do orthogonal
        t_start = time.time()
        o_x, o_lbd, o_ctr, converge = orthogonal_newton_correction_method(
            A, max_itr, max_err, x_init=x0)
        t_end = time.time()
        o_ncm_cnt[jj] = o_ctr
        o_ncm_lbd[jj] = o_lbd
        o_ncm_err[jj] = np.linalg.norm(
            symmetric_tv_mode_product(A, o_x, m - 1) - o_lbd * o_x)
        o_ncm_time[jj] = t_end - t_start

        # do schur_form_rayleigh
        t_start = time.time()
        if False:
            s_x, s_lbd, ctr, converge = schur_form_rayleigh(A,
                                                            max_itr,
                                                            max_err,
                                                            x_init=x0)
        else:
            # s_x, s_lbd, ctr, converge = schur_form_rayleigh_chebyshev_linear(
            # A, max_itr, max_err, x_init=x0, do_chebyshev=True)
            s_x, s_lbd, ctr, converge, err = schur_form_rayleigh_chebyshev(
                A, max_itr, max_err, x_init=x0, do_chebyshev=False)

        t_end = time.time()
        schur_cnt[jj] = ctr
        schur_lbd[jj] = s_lbd
        schur_err[jj] = np.linalg.norm(
            symmetric_tv_mode_product(A, s_x, m - 1) - s_lbd * s_x)
        schur_time[jj] = t_end - t_start

        # now do rayleigh

        t_start = time.time()
        res_ray = rayleigh_quotient_iteration(e,
                                              x0,
                                              max_err=max_err,
                                              max_iter=max_itr,
                                              verbose=False,
                                              exit_by_diff=True)
        t_end = time.time()
        ray_time[jj] = t_end - t_start
        ray_cnt[jj] = res_ray['n_iter']
        ray_lbd[jj] = res_ray['lbd']
        ray_err[jj] = np.linalg.norm(res_ray['err'])
        # print("doing rayleigh")
        # print(res_ray)
        # print(e.L(res_ray['x'], res_ray['lbd']))

        # now do rayleigh chebyshev
        t_start = time.time()
        if True:
            sch_x, sch_lbd, ctr, converge, err = schur_form_rayleigh_chebyshev(
                A, max_itr, max_err, x_init=x0, do_chebyshev=True)
        else:
            sch_x, sch_lbd, ctr, converge = schur_form_rayleigh_linear(
                A, max_itr, max_err, x_init=x0, u=None)
        t_end = time.time()
        """
        res_ray_cheb = rayleigh_chebyshev(
            e, x0, max_err=max_err, max_iter=max_itr,
            verbose=False, exit_by_diff=True)
        """

        schur_cheb_time[jj] = t_end - t_start
        schur_cheb_cnt[jj] = ctr
        schur_cheb_lbd[jj] = sch_lbd
        schur_cheb_err[jj] = np.linalg.norm(
            symmetric_tv_mode_product(A, sch_x, m - 1) - sch_lbd * sch_x)
        schur_cheb_time[jj] = t_end - t_start

        # print("doing raychev")
        # print(res_ray_cheb)
        # print(e.L(res_ray_cheb['x'], res_ray_cheb['lbd']))

    summ = pd.DataFrame(
        {
            'o_ncm_iter': o_ncm_cnt,
            'schur_iter': schur_cnt,
            'ray_iter': ray_cnt,
            'schur_cheb_iter': schur_cheb_cnt,
            'o_ncm_err': o_ncm_err,
            'schur_err': schur_err,
            'ray_err': ray_err,
            'schur_cheb_err': schur_cheb_err,
            'o_ncm_lbd': o_ncm_lbd,
            'schur_lbd': schur_lbd,
            'ray_lbd': ray_lbd,
            'schur_cheb_lbd': schur_cheb_lbd,
            'o_ncm_time': o_ncm_time,
            'schur_time': schur_time,
            'ray_time': ray_time,
            'schur_cheb_time': schur_cheb_time
        },
        columns=[
            'o_ncm_iter', 'o_ncm_lbd', 'o_ncm_err', 'o_ncm_time', 'schur_iter',
            'schur_lbd', 'schur_err', 'schur_time', 'ray_iter', 'ray_lbd',
            'ray_err', 'ray_time', 'schur_cheb_iter', 'schur_cheb_lbd',
            'schur_cheb_err', 'schur_cheb_time'
        ])
    return summ
Пример #2
0
def _test_eigen_linear():
    """
    with linear constraint
    we try two ways to do Rayleigh / Rayleigh Chebysev
    with HT = H.T and HT = z.T
    """
    np.random.seed(0)
    k = 5

    x0 = np.random.randint(-5, 5, k) / 10.
    x0 = x0 / np.linalg.norm(x0)

    # need ||z|| = 1
    z = x0.copy()

    def hyperplan_func(x):
        return np.dot(z.T, x) - 1

    def hyperplan_jacobian(x):
        return z.reshape(1, -1)

    def hyperplan_retraction(x, u):
        # return x + u
        x0 = x + u
        return x0 + (1 - np.dot(z, x0)) * z
    
    hyperplan = base_constraints(
        shape_in=(k,),
        shape_constraint=(1,),
        equality=hyperplan_func)

    hyperplan.set_analytics(
        J_C=hyperplan_jacobian,
        retraction=hyperplan_retraction)

    A = utils.gen_random_symmetric(k)
    
    def HT(x):
        return z.T
    
    e = eigen_ht_lagrange(A, z, HT)
    e.constraints = hyperplan
    res_e = explicit_newton_raphson(
        e, x0, np.array([1.]), feasible=False)
    print(res_e)
    ei, v = np.linalg.eigh(A)
    print(ei)
    print(v)
    # now do retraction:
    res_f = explicit_newton_raphson(
        e, x0, np.array([1.]), feasible=True)
    print(res_f)
    
    res_cheb = explicit_chebyshev(
        e, x0, np.array([1.]), feasible=False, verbose=True)
    print(res_cheb)

    res_cheb = explicit_chebyshev(
        e, x0, np.array([1.]), feasible=True, verbose=True)
    print(e.L(res_cheb['x'], res_cheb['lbd']))
    print(res_cheb)

    for i in range(10):
        x0 = np.random.randint(-5, 5, k) / 10.
        x0 = x0 / np.linalg.norm(x0)

        res_ray = rayleigh_quotient_iteration(e, x0, verbose=False)
        print(res_ray)
        # print(e.L(res_ray['x'], res_ray['lbd']))

        # now do rayleigh chebyshev        
        res_ray_cheb = rayleigh_chebyshev(e, x0, verbose=False, cutoff=3e-1)
        # print(e.L(res_ray_cheb['x'], res_ray_cheb['lbd']))
        print(res_ray_cheb)

    n_test = 1000
    tbl = np.full((n_test, 6), np.nan)

    for i in range(n_test):
        x0 = np.random.randint(-5, 5, k) / 10.
        x0 = x0 / np.linalg.norm(x0)
        try:
            res_ray = rayleigh_quotient_iteration(e, x0, verbose=False)
            tbl[i, 0] = res_ray['n_iter']
            tbl[i, 1] = res_ray['lbd']
            tbl[i, 2] = np.linalg.norm(res_ray['err'])
        except Exception:
            pass

        # now do rayleigh chebyshev
        try:
            res_ray_cheb = rayleigh_chebyshev(e, x0, verbose=False, cutoff=3e-1)
            tbl[i, 3] = res_ray_cheb['n_iter']
            tbl[i, 4] = res_ray_cheb['lbd']
            tbl[i, 5] = np.linalg.norm(res_ray_cheb['err'])
        except Exception:
            pass
    print(np.nanmean(tbl, axis=0))

    # example 2 non symmetric
    B = utils.gen_random_real_eigen(k)
    en = eigen_ht_lagrange(B, z, HT)
    en.constraints = hyperplan
    res_e = explicit_newton_raphson(
        en, x0, np.array([1.]), feasible=False)
    print(res_e)
    print(en.L(res_e['x'], res_e['lbd']))
    print(en.constraints.equality(res_e['x']))

    ei, v = np.linalg.eig(B)
    print(ei)
    print(v)
    # now do retraction:
    res_f = explicit_newton_raphson(
        en, x0, np.array([1.]), feasible=True, verbose=True)
    print(res_f)
    print(en.L(res_f['x'], res_f['lbd']))
    print(en.constraints.equality(res_f['x']))

    res_chev = explicit_chebyshev(
        en, x0, np.array([1.]), feasible=False, verbose=True)
    print(res_chev)
    print(en.L(res_chev['x'], res_chev['lbd']))
    print(en.constraints.equality(res_chev['x']))

    res_chev = explicit_chebyshev(
        en, x0, np.array([1.]), feasible=True, verbose=True)
    print(res_chev)
    print(en.L(res_chev['x'], res_chev['lbd']))
    print(en.constraints.equality(res_chev['x']))

    for i in range(10):
        x0 = np.random.randint(-5, 5, k) / 10.
        x0 = x0 / np.linalg.norm(x0)
        print("Do rayleigh")
        res_ray = rayleigh_quotient_iteration(en, x0, verbose=False)
        print(res_ray)
        # print(en.L(res_ray['x'], res_ray['lbd']))

        # now do rayleigh chebyshev
        print("Do rayleigh chebyshev")
        res_ray_cheb = rayleigh_chebyshev(en, x0, verbose=False, cutoff=1.e-1)
        print(en.L(res_ray_cheb['x'], res_ray_cheb['lbd']))
        print(res_ray_cheb)

    n_test = 1000
    tbl2 = np.full((n_test, 6), np.nan)

    for i in range(n_test):
        x0 = np.random.randint(-5, 5, k) / 10.
        x0 = x0 / np.linalg.norm(x0)
        try:
            res_ray = rayleigh_quotient_iteration(en, x0, verbose=False)
            tbl2[i, 0] = res_ray['n_iter']
            tbl2[i, 1] = res_ray['lbd']
            tbl2[i, 2] = np.linalg.norm(res_ray['err'])
        except Exception:
            pass
        try:
            res_ray_cheb = rayleigh_chebyshev(en, x0, verbose=False, cutoff=2.e-1)
            tbl2[i, 3] = res_ray_cheb['n_iter']
            tbl2[i, 4] = res_ray_cheb['lbd']
            tbl2[i, 5] = np.linalg.norm(res_ray_cheb['err'])
        except Exception:
            pass

    print(np.nanmean(tbl2, axis=0))

    # now change method dont use HT
    def calc_J_RAYLEIGH(self, x):
        xsq = np.sum(x * x)
        return (- 2. / (xsq * xsq) * self['RAYLEIGH'] * x.T + np.dot(
            x.T / xsq, self._args['A'] + self._args['A'].T)).reshape(1, -1)
    eigen_ht_lagrange.calc_J_RAYLEIGH = calc_J_RAYLEIGH    

    en1 = eigen_ht_lagrange(B, z)
    en1.constraints = hyperplan

    for i in range(10):
        x0 = np.random.randint(-5, 5, k) / 10.
        x0 = x0 / np.linalg.norm(x0)

        res_ray1 = rayleigh_quotient_iteration(en1, x0, verbose=False)
        print(res_ray1)
        # print(en1.L(res_ray1['x'], res_ray1['lbd']))

        res_ray_cheb1 = rayleigh_chebyshev(
            en1, x0, verbose=False, cutoff=5e-1)
        print(en1.L(res_ray_cheb1['x'], res_ray_cheb1['lbd']))
        print(res_ray_cheb1)
Пример #3
0
def _test_nonlinear_parametrized_constraints():
    """ Allow for multiple constraints
    F(X) is of simple form A X + sin(Bx)
    more complex H
    May not converge if see bad results try a different initial point
    """

    nonlinear_constraint = True
    if nonlinear_constraint:

        def func1(x):
            return np.sum(-2 * x + np.sin(x))

        def func2(x):
            return np.sum(x + np.cos(x))

        def deriv1(x):
            return -2 + np.cos(x)

        def deriv2(x):
            return 1 - np.sin(x)

        def second_deriv1(x):
            return np.diag(-np.sin(x))

        def second_deriv2(x):
            return np.diag(-np.cos(x))

        def H(x):
            ret = np.zeros((x.shape[0], 2))
            ret[:, 0] = (x * x)[:]
            ret[:, 1] = x[:]
            return ret

        def calc_J_H(x):
            ret = np.zeros((x.shape[0], 2, x.shape[0]))
            ret[:, 0, :] = np.diag(2 * x)
            ret[:, 1, :] = np.eye(x.shape[0])
            return ret

        def calc_J_H2(x):
            ret = np.zeros((x.shape[0], 2, x.shape[0], x.shape[0]))
            for i in range(x.shape[0]):
                ret[i, 0, i, i] = 2
            return ret

    else:

        def func1(x):
            return np.sum(x) - 1

        def func2(x):
            return np.sum(x * np.arange(x.shape[0])) - 1

        def deriv1(x):
            return x

        def deriv2(x):
            return np.arange(x.shape[0])

        def second_deriv1(x):
            return np.eye(x.shape[0])

        def second_deriv2(x):
            return np.zeros((x.shape[0], x.shape[0]), dtype=float)

        def H(x):
            ret = np.zeros((x.shape[0], 2))
            ret[:-1, 0] = 1
            ret[:-2, 1] = np.arange(x.shape[0] - 2)
            ret[-2, 0] = -1
            ret[-1, 1] = -1
            return ret

        def calc_J_H(x):
            ret = np.zeros((x.shape[0], 2, x.shape[0]))
            return ret

        def calc_J_H2(x):
            return np.zeros((x.shape[0], 2, x.shape[0], x.shape[0]))

    n_var = 3
    funcs = [func1, func2]
    derivs = [deriv1, deriv2]

    n_func = len(funcs)
    n = n_func + n_var
    V = np.random.randint(-10, 10, (n, n))
    D = np.diag(np.random.randint(-10, 10, n))
    A = np.dot(np.dot(V, D), np.linalg.inv(V))
    B = np.random.randint(-10, 10, (n, n)).astype(float) * 1e-4

    def gen_start_point():
        x1a = np.random.randint(-5, 5, n_var) / 10.

        x1 = np.zeros((n_var + len(funcs)))
        x1[:n_var] = x1a
        x1[n_var:] = np.array([funcs[ix](x1a) for ix in range(n_func)])
        return x1

    x0 = gen_start_point()
    lbd0 = np.array([1., 1.])
    e = vector_nonlinear_lagrange(A, B, H, calc_J_H)
    misc_constr = parametrized_constraints((n, ), funcs, derivs)

    e.constraints = misc_constr

    x0 = gen_start_point()
    res_e = explicit_newton_raphson(e, x0, lbd0, feasible=False)
    print(res_e)
    """
    ei, v = np.linalg.eig(A)
    print ei
    print v
    """
    # now do retraction:
    x1 = gen_start_point()
    res_f = explicit_newton_raphson(e,
                                    x1,
                                    res_e['lbd'] + .3,
                                    max_err=1e-3,
                                    feasible=True,
                                    verbose=True)

    print(res_f)

    # res_ray = rayleigh_quotient_iteration(
    # e, x0)
    for i in range(10):
        x1 = gen_start_point()
        try:
            res_ray = rayleigh_quotient_iteration(e, x1)
            print('x1= %s ' % str(x1))
            print(res_ray)
        except Exception:
            pass

    for i in range(10):
        # now try chebyshev
        try:
            second_derivs = [second_deriv1, second_deriv2]
            echeb = vector_nonlinear_lagrange(A, B, H, calc_J_H, calc_J_H2)
            cheb_constr = parametrized_constraints((n, ), funcs, derivs,
                                                   second_derivs)
            echeb.constraints = cheb_constr

            x0 = res_ray['x'] + .3
            lbd0 = res_ray['lbd'] + .3
            res_cheb = explicit_chebyshev(echeb, x0, lbd0, feasible=False)
            print(res_cheb)
            break
        except Exception:
            pass
    # rayleigh_chebyshev
    for i in range(10):
        x1 = gen_start_point()
        try:
            res_ray_chev = rayleigh_chebyshev(echeb, x1)
            print(res_ray_chev)
        except Exception:
            pass
Пример #4
0
def _test_eigenvector():
    np.random.seed(0)
    k = 5

    x0 = np.random.randint(-5, 5, k) / 10.
    x0 = x0 / np.linalg.norm(x0)

    def sphere_func(x):
        return np.dot(x.T, x) - 1

    def sphere_jacobian(x):
        return 2 * x.reshape(1, -1)

    def sphere_retraction(x, u):
        return (x + u) / np.linalg.norm(x + u)
    
    sphere = base_constraints(
        shape_in=(k,),
        shape_constraint=(1,),
        equality=sphere_func)

    sphere.set_analytics(
        J_C=sphere_jacobian,
        retraction=sphere_retraction)

    A = utils.gen_random_symmetric(k)
    e = eigen_vector_lagrange(A)
    e.constraints = sphere
    res_e = explicit_newton_raphson(
        e, x0, np.array([1.]), feasible=False, verbose=True)
    print(res_e)
    ei, v = np.linalg.eigh(A)
    print(ei)
    print(v)
    # now do retraction:
    for i in range(10):
        x1 = np.random.randint(-5, 5, k) / 10.
        x1 = x1 / np.linalg.norm(x1)

        res_f = explicit_newton_raphson(
            e, x1, np.array([1.]), feasible=True, verbose=False)
        print(res_f)
        print(e.L(res_f['x'], res_f['lbd']))

    # now do explicit_chebyshev
    
    res_chev = explicit_chebyshev(
        e, x0, np.array([1.]), feasible=False, verbose=True)
    print(res_chev)

    res_chev_f = explicit_chebyshev(
        e, x0, np.array([1.]), feasible=True, verbose=True)
    print(res_chev_f)

    for i in range(10):
        x0 = np.random.randint(-5, 5, k) / 10.
        x0 = x0 / np.linalg.norm(x0)

        # now do rayleigh
        res_ray = rayleigh_quotient_iteration(e, x0, verbose=False)
        print(res_ray)
        # print(e.L(res_ray['x'], res_ray['lbd']))
        # now do rayleigh chebyshev
        res_ray_cheb = rayleigh_chebyshev(e, x0, verbose=False)
        print(res_ray_cheb)

    n_test = 1000
    tbl = np.zeros((n_test, 6))
    for i in range(n_test):
        x0 = np.random.randint(-5, 5, k) / 10.
        x0 = x0 / np.linalg.norm(x0)

        # now do rayleigh
        res_ray = rayleigh_quotient_iteration(e, x0, verbose=False)
        tbl[i, 0] = res_ray['n_iter']
        tbl[i, 1] = res_ray['lbd']
        tbl[i, 2] = np.linalg.norm(res_ray['err'])
        # print(res_ray)
        # print(e.L(res_ray['x'], res_ray['lbd']))
        # now do rayleigh chebyshev
        res_ray_cheb = rayleigh_chebyshev(e, x0, verbose=False)
        # print(res_ray_cheb)
        tbl[i, 3] = res_ray_cheb['n_iter']
        tbl[i, 4] = res_ray_cheb['lbd']
        tbl[i, 5] = np.linalg.norm(res_ray_cheb['err'])
    print(np.mean(tbl, axis=0))
            
    # now do the non symmetric case
    B = utils.gen_random_real_eigen(k)
    e = eigen_vector_lagrange(B)
    e.constraints = sphere
    res_e = explicit_newton_raphson(
        e, x0, np.array([1.]), feasible=False, verbose=True)
    print(res_e)
    ei, v = np.linalg.eig(B)
    print(ei)
    print(v)
    # now do retraction:
    res_f = explicit_newton_raphson(
        e, x0, np.array([1.]), feasible=True, verbose=True)
    print(res_f)

    res_chev = explicit_chebyshev(
        e, x0, np.array([1.]), feasible=False, verbose=True)
    print(res_chev)

    res_chev = explicit_chebyshev(
        e, x0, np.array([1.]), feasible=True, verbose=True)
    print(res_chev)

    n_test = 10
    for i in range(n_test):
        x0 = np.random.randint(-5, 5, k) / 10.
        x0 = x0 / np.linalg.norm(x0)

        print("Doing Rayleigh")
        res_ray = rayleigh_quotient_iteration(e, x0, verbose=False)
        print(res_ray)
        # print(e.L(res_ray['x'], res_ray['lbd']))

        # now do rayleigh chebyshev
        print("Doing Rayleigh Chebysev")
        res_ray_cheb = rayleigh_chebyshev(e, x0, verbose=False, cutoff=1e-1)
        print(res_ray_cheb)

    n_test = 1000
    tbl2 = np.full((n_test, 6), np.nan)
    from lagrange_rayleigh.core import solver
    solver._MAX_ERR = 1e-10
    solver._MAX_ITER = 200
    for i in range(n_test):
        x0 = np.random.randint(-5, 5, k) / 10.
        x0 = x0 / np.linalg.norm(x0)
        B = utils.gen_random_real_eigen(k)
        e = eigen_vector_lagrange(B)
        e.constraints = sphere

        res_ray = rayleigh_quotient_iteration(
            e, x0, max_err=1e-8, verbose=False)
        if np.linalg.norm(res_ray['err']) < .01:
            tbl2[i, 0] = res_ray['n_iter']
            tbl2[i, 1] = res_ray['lbd']
            tbl2[i, 2] = np.linalg.norm(res_ray['err'])

        # print("Doing Rayleigh Chebysev")
        try:
            res_ray_cheb = rayleigh_chebyshev(
                e, x0, max_err=1e-8, verbose=False, cutoff=2e-1)
            if np.linalg.norm(res_ray_cheb['err']) < .01:
                tbl2[i, 3] = res_ray_cheb['n_iter']
                tbl2[i, 4] = res_ray_cheb['lbd']
                tbl2[i, 5] = np.linalg.norm(res_ray_cheb['err'])
        except Exception:
            pass
    print(np.nanmean(tbl2, axis=0))
Пример #5
0
def _test_invariance_subspace():
    from lagrange_rayleigh.core.utils import gen_random_symmetric
    from lagrange_rayleigh.core.solver import explicit_newton_raphson
    from lagrange_rayleigh.core.solver import rayleigh_quotient_iteration
    # from lagrange_rayleigh.core.solver import explicit_chebyshev, rayleigh_chebyshev

    np.random.seed(0)
    n = 7
    p = 2
    A = gen_random_symmetric(n)

    sc = stiefel(n, p)
    ei, v = np.linalg.eigh(A)
    
    x0a = np.random.randint(-5, 5, (n, p)) / 10.
    x0 = sc.retraction(x0a, 0)
    iv = invariant_subspace(A)
    iv.constraints = sc
    lbd0 = np.dot(x0.T, np.dot(A, x0))
    
    res_e = explicit_newton_raphson(
        iv, x0, lbd0, feasible=False, verbose=True)
    print(res_e)

    x0a = np.random.randint(-5, 5, (n, p)) / 10.
    x0 = sc.retraction(x0a, 0)
    lbd0 = np.dot(x0.T, np.dot(A, x0))
    res_f = explicit_newton_raphson(
        iv, x0, lbd0, max_err=1e-3,
        feasible=True, verbose=True)
    print(res_f)
    
    x0a = np.random.randint(-5, 5, (n, p)) / 10.
    x0 = sc.retraction(x0a, 0)
    lbd0 = np.dot(x0.T, np.dot(A, x0))
    res_ray = rayleigh_quotient_iteration(iv, x0, verbose=True)
    print(res_ray)
    print(iv.L(res_ray['x'], res_ray['lbd']))

    def make_y(x, lbd):
        y = np.zeros(n*p + (p * (p+1)) // 2)
        y[:n*p] = x.T.reshape(-1)
        y[n*p:] = flatten_symmetric(lbd)
        return y

    def LL(y):
        """
        y[:n*p] is x
        y[n:] is lbd
        """
        x = y[:n*p].reshape(p, n).T
        ret = np.zeros_like(y)
        L = np.dot(A, x) - np.dot(x, make_symmetric(y[n*p:]))
        ret[:n*p] = L.T.reshape(-1)
        ret[n*p:] = flatten_symmetric(np.dot(x.T, x) - np.eye(p))
        return ret

    def parse_y(y):
        x = y[:n*p].reshape(p, n).T
        lbd = make_symmetric(y[n*p:])
        return x, lbd

    def check_y(y):
        x, lbd = parse_y(y)
        return np.dot(A, x) - np.dot(x, lbd), np.dot(x.T, x) - np.eye(p)
                                            
    def J_LL(y):
        x, lbd = parse_y(y)
        jac = np.zeros((y.shape[0], y.shape[0]))
        for i in range(p):
            jac[i*n:(i+1)*n, i*n:(i+1)*n] = A
        for i1 in range(p):
            for i2 in range(p):
                for i_n in range(n):
                    jac[i1*n+i_n, i2*n+i_n] -= lbd[i1, i2]

        # derivatives with respect to lbd:

        for i1 in range(p):
            si1 = (i1*(i1+1)) // 2
            for i2 in range(i1):
                jac[i2*n:i2*n+n, n*p+si1+i2] = -x[:, i1]
                jac[i1*n:i1*n+n, n*p+si1+i2] = -x[:, i2]
            jac[i1*n:i1*n+n, n*p+si1+i1] = -x[:, i1]

        # derivatives of constraints
        for i1 in range(p):
            si = (i1 * (i1 + 1)) // 2
            jac[n*p+si+i1, i1*n:i1*n+n] = 2 * x[:, i1]
            for i2 in range(i1):
                jac[n*p + si + i2, i1*n:i1*n+n] = x[:, i2]
                jac[n*p + si + i2, i2*n:i2*n+n] = x[:, i1]

        return jac
        
    from scipy.optimize import fsolve
    y0 = np.zeros(n*p + (p * (p+1)) // 2)
    y0[:n*p] = x0.T.reshape(-1)
    y0[n*p:] = flatten_symmetric(lbd0)
    ee = 1e-4
    jl1 = np.zeros((y0.shape[0], y0.shape[0]))
    for ix in range(y0.shape[0]):
        # v = np.arange(1, y0.shape[0]+1) * 1e-4
        v = np.zeros_like(y0)
        v[ix] = ee
        jl1[:, ix] = (LL(y0 + v) - LL(y0)) / ee
    ijl1 = np.linalg.inv(jl1)
    res = fsolve(LL, y0)
    res1 = fsolve(LL, y0, fprime=J_LL)

    yy = y0.copy()
    i = 0
    l1 = np.array([100.])
    while np.linalg.norm(l1) > 1e-4:
        l1 = LL(yy)
        j1 = J_LL(yy)
        diff = np.linalg.solve(j1, l1)
        yy = yy - diff
        print('i=%d l1=%s' % (i, l1))
        i += 1
    xres, lbdres = parse_y(yy)
    
    print(res)
    print(res1)