Пример #1
0
def _parse_shocks(optim_paras, params):
    """Parse the shock parameters and create the Cholesky factor."""
    if sum(f"shocks_{i}" in params.index for i in ["sdcorr", "cov", "chol"]) >= 2:
        raise ValueError("It is not allowed to define multiple shock matrices.")
    elif "shocks_sdcorr" in params.index:
        sorted_shocks = _sort_shocks_sdcorr(optim_paras, params.loc["shocks_sdcorr"])
        cov = sdcorr_params_to_matrix(sorted_shocks)
        optim_paras["shocks_cholesky"] = robust_cholesky(cov)
    elif "shocks_cov" in params.index:
        sorted_shocks = _sort_shocks_cov_chol(
            optim_paras, params.loc["shocks_cov"], "cov"
        )
        cov = cov_params_to_matrix(sorted_shocks)
        optim_paras["shocks_cholesky"] = robust_cholesky(cov)
    elif "shocks_chol" in params.index:
        sorted_shocks = _sort_shocks_cov_chol(
            optim_paras, params.loc["shocks_chol"], "chol"
        )
        optim_paras["shocks_cholesky"] = chol_params_to_lower_triangular_matrix(
            sorted_shocks
        )
    else:
        raise NotImplementedError

    return optim_paras
Пример #2
0
def covariance_from_internal_jacobian(internal_values, constr):
    r"""Jacobian of ``covariance_from_internal``.

    The following result is motivated by https://tinyurl.com/y4pbfxst, which is
    shortly presented again here. For notation see the explaination at the
    beginning of the module.


    Explaination of the result
    --------------------------

    We want to differentiate the graph
                internal --> cholesky --> cov --> external

    Define :math:`x' := \text{vec}(X)` and :math:`c' := \text{vec}(S)`, where
    :math:`X` denotes the Cholesky factor of the covariance matrix :math:`S`.
    We then first differentiate the part "cholesky --> cov" using the result
    stated in the tinyurl above to get

    .. math::
        J' := \frac{\mathrm{d}c'}{\mathrm{d}x'} = (I + K)(X \otimes I) \,,

    where :math:`K` denotes the commutation matrix. Using this intermediate
    result we can compute the jacobian as

    .. math:: \frac{\mathrm{d}c}{\mathrm{d}x} = L J' D \,,

    where :math:`c := \text{external}` and :math:`x := \text{internal}`.

    Args:
        internal_values (np.ndarray): Cholesky factors stored in an "internal"
            format.

    Returns:
        deriv: The Jacobian matrix.

    """
    chol = chol_params_to_lower_triangular_matrix(internal_values)
    dim = len(chol)

    K = _commutation_matrix(dim)
    L = _elimination_matrix(dim)

    left = np.eye(dim ** 2) + K
    right = np.kron(chol, np.eye(dim))

    intermediate = left @ right

    deriv = L @ intermediate @ L.T
    return deriv
Пример #3
0
def _parse_shocks(optim_paras, params):
    """Parse the shock parameters and create the Cholesky factor."""
    if sum(f"shocks_{i}" in params.index for i in ["sdcorr", "cov", "chol"]) >= 2:
        raise ValueError("It is not allowed to define multiple shock matrices.")
    elif "shocks_sdcorr" in params.index:
        cov = sdcorr_params_to_matrix(params.loc["shocks_sdcorr"])
        optim_paras["shocks_cholesky"] = robust_cholesky(cov)
    elif "shocks_cov" in params.index:
        cov = cov_params_to_matrix(params.loc["shocks_cov"])
        optim_paras["shocks_cholesky"] = robust_cholesky(cov)
    elif "shocks_chol" in params.index:
        optim_paras["shocks_cholesky"] = chol_params_to_lower_triangular_matrix(
            params.loc["shocks_chol"]
        )
    else:
        raise KeyError("No shock matrix is specified.")

    return optim_paras
Пример #4
0
def test_chol_params_to_lower_triangular_matrix():
    calculated = chol_params_to_lower_triangular_matrix(pd.Series([1, 2, 3]))
    expected = np.array([[1, 0], [2, 3]])
    aaae(calculated, expected)
Пример #5
0
def covariance_from_internal(internal_values, constr):
    """Undo a cholesky reparametrization."""
    chol = chol_params_to_lower_triangular_matrix(internal_values)
    cov = chol @ chol.T
    return cov[np.tril_indices(len(chol))]
Пример #6
0
def sdcorr_from_internal_jacobian(internal_values, constr):
    r"""Derivative of ``sdcorr_from_internal``.

    The following result is motivated by https://tinyurl.com/y6ytlyd9; however
    since the question was formulated with an error the result here is adjusted
    slightly. In particular, in the answer by user 'greg', the matrix :math:`A`
    should have been defined as :math:`A = \text{diag}(||x_1||, \dots, ||x_n||)`
    , where :math:`||x_i||` denotes the euclidian norm of the the i-th row of
    :math:`X` (the Cholesky factor). For notation see the explaination at the
    beginning of the module or the question on the tinyurl. The variable names
    in this function are chosen to be consistent with the tinyurl link.

    Explaination on the result
    --------------------------

    We want to differentiate the graph

     internal --> cholesky --> cov --> corr-mat --> mod. corr-mat --> external

    where mod. corr-mat denotes the modified correlation matrix which has the
    standard deviations stored on its diagonal. Let :math:`x := \text{internal}`
    and :math:`p := \text{external}`. Then we want to compute the quantity

    .. math:: \frac{\mathrm{d} p}{\mathrm{d} x} .

    As before we consider an intermediate result first. Namely we define
    :math:`A` as above, :math:`V := A^{-1}` and :math:`P := V S V + A - I`. The
    attentive reader might now notice that :math:`P` is the modified correlation
    matrix. At last we write :math:`x' := \text{vec}(X)` and
    :math:`p' := \text{vec}(P)`. Using the result stated in the tinyurl above,
    adjusted for the different matrix :math:`A`, we can compute the quantity
    :math:`(\mathrm{d} p'/ \mathrm{d} x')`.

    Finally, since we can define transformation matrices :math:`T` and :math:`L`
    to get :math:`p = T p'` and :math:`x = L x'` (where :math:`L` denotes the
    elimination matrix with corresponding duplication matrix :math:`D`), we can
    get our final result as

    .. math::
        \frac{\mathrm{d}p}{\mathrm{d}x} = T \frac{\mathrm{d}p'}{\mathrm{d}x'} D

    Args:
        internal_values (np.ndarray): Cholesky factors stored in an "internal"
            format.

    Returns:
        deriv: The Jacobian matrix.

    """
    X = chol_params_to_lower_triangular_matrix(internal_values)
    dim = len(X)

    identity = np.eye(dim)
    S = X @ X.T

    #  the wrong formulation in the tinyurl stated: A = np.multiply(I, X)
    A = np.sqrt(np.multiply(identity, S))

    V = np.linalg.inv(A)

    K = _commutation_matrix(dim)
    Y = np.diag(identity.ravel("F"))

    #  with the wrong formulation in the tinyurl we would have had U = Y
    norms = np.sqrt((X ** 2).sum(axis=1).reshape(-1, 1))
    XX = X / norms
    U = Y @ np.kron(identity, XX) @ K

    N = np.kron(identity, X) @ K + np.kron(X, identity)

    VS = V @ S
    B = np.kron(V, V)
    H = np.kron(VS, identity)
    J = np.kron(identity, VS)

    intermediate = U + B @ N - (H + J) @ B @ U

    T = _transformation_matrix(dim)
    D = _duplication_matrix(dim)

    deriv = T @ intermediate @ D
    return deriv
Пример #7
0
def sdcorr_from_internal(internal_values, constr):
    """Undo a cholesky reparametrization."""
    chol = chol_params_to_lower_triangular_matrix(internal_values)
    cov = chol @ chol.T
    return cov_matrix_to_sdcorr_params(cov)