Пример #1
0
def make_positive_definite(m, tol=None):
    ''' Computes a matrix close to the original matrix m that is positive definite.
    This function is just a transcript of R' make.positive.definite function.
    m (2d array): A matrix that is not necessary psd.
    tol (int): A tolerence level controlling how "different" the psd matrice
                can be from the original matrix
    ---------------------------------------------------------------
    returns (2d array): A psd matrix
    '''
    d = m.shape[0]
    if (m.shape[1] != d):
        raise RuntimeError("Input matrix is not square!")
    eigvalues, eigvect = eigh(m)

    # Sort the eigen values
    idx = eigvalues.argsort()[::-1]
    eigvalues = eigvalues[idx]
    eigvect = eigvect[:, idx]

    if (tol == None):
        tol = d * np.max(np.abs(eigvalues)) * sys.float_info.epsilon
    delta = 2 * tol
    tau = np.maximum(0, delta - eigvalues)
    dm = multi_dot([eigvect, np.diag(tau), eigvect.T])
    return (m + dm)
Пример #2
0
def plot_single(result, x_opt, f_opt, method):
    # Unpack result
    t_hist = result['t_hist']
    x_hist = result['x_hist']
    f_hist = result['f_hist']
    g_hist = result['g_hist']
    h_hist = result['h_hist']

    # Plot
    fig, ax = plt.subplots(nrows=4, sharex=True, figsize=(6, 10))

    ax[0].semilogy(t_hist, la.norm(x_hist - x_opt, axis=1))
    ax[0].set_ylabel('Iterate error norm')

    ax[1].semilogy(t_hist, f_hist - f_opt)
    ax[1].set_ylabel('Objective error')

    ax[2].semilogy(t_hist, la.norm(g_hist, axis=1))
    ax[3].axhline(MIN_GRAD_NORM, linestyle='--', color='k', alpha=0.5)
    ax[2].set_ylabel('Gradient norm')

    ax[3].plot(t_hist, np.array([la.eigh(h)[0] for h in h_hist]))
    ax[3].axhline(0, linestyle='--', color='k', alpha=0.5)
    ax[3].set_yscale('symlog')
    ax[3].set_ylabel('Hessian eigenvalues')

    ax[-1].set_xlabel('Iteration')
    ax[0].set_title(method)
    return fig, ax
Пример #3
0
def solve_sylvester(a, b, q):
    if a.shape == b.shape:
        axes = (0, 2, 1) if a.ndim == 3 else (1, 0)
        if np.all(a == b) and np.all(np.abs(a - np.transpose(a, axes)) < 1e-12):
            eigvals, eigvecs = eigh(a)
            if np.all(eigvals >= 1e-12):
                tilde_q = np.transpose(eigvecs, axes) @ q @ eigvecs
                tilde_x = tilde_q / (eigvals[..., :, None] + eigvals[..., None, :])
                return eigvecs @ tilde_x @ np.transpose(eigvecs, axes)

    return np.vectorize(
        scipy.linalg.solve_sylvester, signature="(m,m),(n,n),(m,n)->(m,n)"
    )(a, b, q)
Пример #4
0
def diagonal_cond(H_old, psi_old):
    ''' Ensure that Lambda^T Psi^{-1} Lambda is diagonal
    H_old (list of nb_layers elements of shape (K_l x r_l-1, r_l)): The previous
                                        iteration values of Lambda estimators
    psi_old (list of ndarrays): The previous iteration values of Psi estimators
                    (list of nb_layers elements of shape (K_l x r_l-1, r_l-1))
    ------------------------------------------------------------------------
    returns (list of ndarrays): An "identifiable" H estimator (2nd condition)                                          
    '''
    L = len(H_old)

    H = []
    for l in range(L):
        B = np.transpose(H_old[l], (0, 2, 1)) @ pinv(psi_old[l]) @ H_old[l]
        values, vec = eigh(B)
        H.append(H_old[l] @ vec)
    return H
Пример #5
0
def posdefify(A, eps):
    E, V = la.eigh(A)
    return np.dot(V, np.dot(np.diag(np.maximum(E, eps)), V.T))