示例#1
0
def twist_scenarios_mom_match(x, m_, s2_, p=None, method='Riccati', d=None):
    """For details, see here.

    Parameters
    ----------
        x : array, shape (j_,n_) if n_>1 or (j_,) for n_=1
        m_ : array, shape (n_,)
        s2_ : array, shape (n_,n_)
        p : array, optional, shape (j_,)
        method : string, optional
        d : array, shape (k_, n_), optional

    Returns
    -------
        x : array, shape (j_, n_) if n_>1 or (j_,) for n_=1

    """

    if np.ndim(m_) == 0:
        m_ = np.reshape(m_, 1).copy()
    else:
        m_ = np.array(m_).copy()
    if np.ndim(s2_) == 0:
        s2_ = np.reshape(s2_, (1, 1))
    else:
        s2_ = np.array(s2_).copy()
    if len(x.shape) == 1:
        x = x.reshape(-1, 1).copy()

    if p is None:
        j_ = x.shape[0]
        p = np.ones(j_) / j_  # uniform probabilities as default value

    # Step 1. Original moments

    m_x, s2_x = meancov_sp(x, p)

    # Step 2. Transpose-square-root of s2_x

    r_x = transpose_square_root(s2_x, method, d)

    # Step 3. Transpose-square-root of s2_

    r_ = transpose_square_root(s2_, method, d)

    # Step 4. Twist matrix

    b = r_ @ np.linalg.inv(r_x)

    # Step 5. Shift vector

    a = m_.reshape(-1, 1) - b @ m_x.reshape(-1, 1)

    # Step 6. Twisted scenarios

    x_ = (a + b @ x.T).T

    return np.squeeze(x_)
示例#2
0
def simulate_t(mu, sigma2, nu, j_, stoc_rep=None, method='Riccati', d=None):
    """For details, see here.

    Parameters
    ----------
        mu : array, shape (n_,)
        sigma2 : array, shape (n_,n_)
        nu : int
        j_ : int
        stoc_rep : bool, optional
        method : string, optional
        d : array, shape (k_,n_), optional

    Returns
    -------
        x : array, shape(j_,n_) if n_>1 or (j_,) for n_=1

    """

    if isinstance(mu, (list, tuple, np.ndarray)):
        mu = np.array(mu)
        sigma2 = np.array(sigma2)
        n_ = len(mu)
    else:
        n_ = 1
        mu = np.reshape(mu, n_)
        sigma2 = np.reshape(sigma2, (n_, n_))

    if stoc_rep is None:
        stoc_rep = False

    if stoc_rep is False:
        # Step 1: Riccati root
        sigma = transpose_square_root(sigma2, method, d)

        # Step 2: Radial scenarios
        r = np.sqrt(n_ * sp.stats.f.ppf(np.random.rand(j_, 1), n_, nu))

        # Step 3: Normal scenarios
        n = simulate_normal(np.zeros(n_), np.eye(n_), j_).reshape(-1, n_)

        # Step 4: Uniform component
        normalizers = np.linalg.norm(n, axis=1)
        y = n / normalizers[:, None]

        # Step 5: Output
        x = mu + r * y @ sigma

    else:  # Alternative stochastic representation
        # Step 6: Normal scenarios
        n = simulate_normal(np.zeros(n_), sigma2, j_, method,
                            d).reshape(-1, n_)

        # Step 7: Chi-squared scenarios
        v = sp.stats.chi2.ppf(np.random.rand(j_, 1), nu)

        # Step 8: Output
        x = mu + n / np.sqrt(v / nu)

    return np.squeeze(x)
示例#3
0
def multi_r2(s2_u, s2_x, sigma2=None):
    """For details, see here.

    Parameters
    ----------
        s2_u : array, shape(n_, n_)
        s2_x : array, shape(n_, n_)
        s2: array, shape(n_, n_)

    Returns
    -------
        r2 : float

    """

    if sigma2 is None:
        r2 = 1.0 - np.trace(s2_u) / np.trace(s2_x)  # r-squared
    else:
        sigma_cholesky = transpose_square_root(
            sigma2, method='Cholesky')  # Cholesky root
        ss_res = np.trace(
            sp.linalg.solve_triangular(
                sigma_cholesky,
                sp.linalg.solve_triangular(sigma_cholesky, s2_u,
                                           lower=True).T).T)
        ss_tot = np.trace(
            sp.linalg.solve_triangular(
                sigma_cholesky,
                sp.linalg.solve_triangular(sigma_cholesky, s2_x,
                                           lower=True).T).T)
        r2 = 1.0 - ss_res / ss_tot  # r-squared

    return r2
示例#4
0
def simulate_quadn(alpha, beta, gamma, mu, sigma2, j_):
    """For details, see here.

    Parameters
    ----------
        alpha : float
        beta : array, shape(n_,)
        gamma : array, shape(n_, n_)
        mu : array, shape(n_,)
        sigma2 : array, shape(n_, n_)
        j_ : float

    Returns
    -------
        y : array, shape(j_,)
        p_ : array, shape(j_,)
    """
    if np.ndim(beta) == 1:
        n_ = len(beta)
    else:
        n_ = 1

    beta, gamma = np.reshape(beta, (n_, 1)), np.reshape(gamma, (n_, n_))
    mu, sigma2 = np.reshape(mu, (n_, 1)), np.reshape(sigma2, (n_, n_))

    # Step 1: Perform cholesky decomposition of sigma2

    l = transpose_square_root(sigma2, 'Cholesky')

    # Step 2: Compute parameter lambda

    lambd, e = np.linalg.eig(l.T @ gamma @ l)
    lambd = lambd.reshape(-1, 1)

    # Step 3: Compute new parameters beta_tilde and gamma_tilde

    beta_tilde = beta + 2 * gamma @ mu
    gamma_tilde = e.T @ l.T @ beta_tilde

    # Step 4: Generate Monte Carlo scenarios

    z = simulate_normal(np.zeros(n_), np.eye(n_), j_).reshape(-1, n_)
    y = alpha + beta.T @ mu + mu.T @ gamma @ mu + \
        z @ gamma_tilde + z ** 2 @ lambd

    # Step 5: Match expectation and variance by twisting probabilities

    e_y = alpha + beta.T @ mu + mu.T @ gamma @ mu + np.trace(sigma2 @ gamma)
    v_y = 2 * np.trace(np.linalg.matrix_power(gamma @ sigma2, 2)) + \
          beta_tilde.T @ sigma2 @ beta_tilde
    p_ = twist_prob_mom_match(y.reshape(-1, 1), e_y[0], v_y).reshape(-1)

    return np.squeeze(y), np.squeeze(p_)
示例#5
0
def simulate_unif_in_ellips(mu, sigma2, j_):
    """For details, see here.

    Parameters
    ----------
        mu : array, shape (n_,)
        sigma2 : array, shape (n_,n_)
        j_ : int

    Returns
    -------
        x : array, shape(j_,n_)
        r : array, shape (j_,)
        y : array, shape (j,n_)

    """

    n_ = len(mu)

    # Step 1. Riccati root
    sigma = transpose_square_root(sigma2)

    # Step 2. Radial scenarios
    r = (np.random.rand(j_, 1))**(1 / n_)

    # Step 3. Normal scenarios
    n = simulate_normal(np.zeros(n_), np.eye(n_), j_).reshape(-1, n_)

    # Step 4. Uniform component
    normalizers = np.linalg.norm(n, axis=1)
    y = n / normalizers[:, None]

    # Step 5. Output
    x = mu + r * y @ sigma

    return x, r, y
示例#6
0
def saddle_point_quadn(y, alpha, beta, gamma, mu, sigma2):
    """For details, see here.

    Parameters
    ----------
        y : array, shape(j_,)
        alpha : scalar
        beta : array, shape(n_,)
        gamma : array, shape(n_, n_)
        mu : array, shape(n_,)
        sigma2 : array, shape(n_, n_)

    Returns
    -------
        cdf : array, shape(j_,)
        pdf : array, shape(j_,)
    """

    y = np.asarray(y).copy().reshape(-1)
    beta = np.asarray(beta).copy().reshape(-1, 1)
    mu = np.asarray(mu).copy().reshape(-1, 1)
    j_ = len(y)

    # Step 1: Compute the eigenvalues and eigenvectors of l.T @ gamma @ l

    l = transpose_square_root(sigma2, 'Cholesky')
    lam, e = np.linalg.eig(l.T @ gamma @ l)
    lam = lam.reshape(-1, 1)

    # Step 2: Compute transformed parameters

    alpha_tilde = alpha + beta.T @ mu + mu.T @ gamma @ mu
    beta_tilde = beta + 2*gamma @ mu
    gamma_tilde = e.T @ l.T @ beta_tilde

    # Step 3: Compute the log-characteristic function and its derivatives

    # log-characteristic function
    def c_y(w):
        return alpha_tilde * w - 0.5 * np.sum(np.log(1 - 2.*w*lam) -
                                              w**2 * gamma_tilde**2 /
                                              (1 - 2.*w*lam))

    # first derivative
    def c_y_prime(w):
        return alpha_tilde + np.sum(lam / (1 - 2.*w*lam) +
                                    gamma_tilde**2 * (w - w**2 * lam) /
                                    (1 - 2.*w*lam)**2)

    # second derivative
    def c_y_second(w):
        return np.array([np.sum(2. * (lam / (1 - 2.*w*lam))**2 +
                                gamma_tilde**2 / (1 - 2.*w*lam)**3)])

    # Step 4: Find w_hat numerically using Brent's method

    lam_max = np.max(lam)
    lam_min = np.min(lam)
    if lam_max > 0:
        w_max = (1 - 1e-5) / (2 * lam_max)
    else:
        w_max = 1e20

    if lam_min < 0:
        w_min = (1 + 1e-5) / (2 * lam_min)
    else:
        w_min = -1e20
    y_min = c_y_prime(w_min)
    y_max = c_y_prime(w_max)

    # initialize
    w_hat = np.zeros(j_)
    c_y_w_hat = np.zeros(j_)  # c(w_hat)
    c_y_second_w_hat = np.zeros(j_)  # c''(w_hat)

    idx = np.argsort(y)
    w_last = w_min

    for j in range(j_):
        if y[idx[j]] <= y_min:
            w_hat[idx[j]] = w_min
        elif y[idx[j]] >= y_max:
            w_hat[idx[j]] = w_max
        else:
            # Brent’s method for finding the root of the function.
            # Since y is sorted and c_y_prime is a monotone increasing function
            # it is guaranteed that the solution w is in the interval
            # [w_last, w_max].
            w_hat[idx[j]] = brentq(lambda w: c_y_prime(w) - y[idx[j]],
                                   w_last, w_max)
            w_last = w_hat[idx[j]]

        c_y_w_hat[idx[j]] = c_y(w_hat[idx[j]])
        c_y_second_w_hat[idx[j]] = c_y_second(w_hat[idx[j]])

    # Step 5: Compute cdf and pdf

    r = np.sign(w_hat) * np.sqrt(2. * (w_hat * y - c_y_w_hat))
    u = w_hat * np.sqrt(c_y_second_w_hat)
    cdf = norm.cdf(r) - norm.pdf(r) * (1. / u - 1. / r)
    pdf = np.exp(c_y_w_hat - w_hat * y) / np.sqrt(2 * np.pi * c_y_second_w_hat)

    return np.squeeze(cdf), np.squeeze(pdf)