Example #1
0
def get_sobol_indices(coefficients, indices, max_order=2):
    num_terms, num_qoi = coefficients.shape
    variance = np.zeros(num_qoi)
    assert num_terms == indices.shape[1]
    interactions = dict()
    interaction_values = []
    interaction_terms = []
    kk = 0
    for ii in range(num_terms):
        index = indices[:, ii]
        var_contribution = coefficients[ii, :]**2
        non_constant_vars = np.where(index > 0)[0]
        key = hash_array(non_constant_vars)

        if len(non_constant_vars) > 0:
            variance += var_contribution

        if len(non_constant_vars) > 0 and len(non_constant_vars) <= max_order:
            if key in interactions:
                interaction_values[interactions[key]] += var_contribution
            else:
                interactions[key] = kk
                interaction_values.append(var_contribution)
                interaction_terms.append(non_constant_vars)
                kk += 1

    interaction_terms = np.asarray(interaction_terms).T
    interaction_values = np.asarray(interaction_values)

    return interaction_terms, interaction_values / variance
def get_coefficients_for_plotting(pce, qoi_idx):
    coeff = pce.get_coefficients()[:, qoi_idx]
    indices = pce.indices.copy()
    assert coeff.shape[0] == indices.shape[1]

    num_vars = pce.num_vars()
    degree = -1
    indices_dict = dict()
    max_degree = indices.sum(axis=0).max()
    for ii in range(indices.shape[1]):
        key = hash_array(indices[:, ii])
        indices_dict[key] = ii
    i = 0
    degree_breaks = []
    coeff_sorted = []
    degree_indices_set = np.empty((num_vars, 0))
    for degree in range(max_degree+1):
        nterms = nchoosek(num_vars+degree, degree)
        if nterms < 1e6:
            degree_indices = compute_hyperbolic_level_indices(
                num_vars, degree, 1.)
        else:
            'Could not plot coefficients of terms with degree >= %d' % degree
            break
        degree_indices_set = np.hstack((degree_indices_set, indices))
        for ii in range(degree_indices.shape[1]-1, -1, -1):
            index = degree_indices[:, ii]
            key = hash_array(index)
            if key in indices_dict:
                coeff_sorted.append(coeff[indices_dict[key]])
            else:
                coeff_sorted.append(0.0)
            i += 1
        degree_breaks.append(i)

    return np.array(coeff_sorted), degree_indices_set, degree_breaks
def multiply_multivariate_polynomials(indices1, coeffs1, indices2, coeffs2):
    """
    TODO: instead of using dictionary to colect terms consider using

    unique_indices,repeated_idx=np.unique(
        indices[active_idx,:],axis=1,return_inverse=True)

    as is done in multivariate_polynomials.conditional_moments_of_polynomial_chaos_expansion. Choose which one is faster


    Parameters
    ----------
    index : multidimensional index
        multidimensional index specifying the polynomial degree in each
        dimension

    Returns
    -------
    """
    num_vars = indices1.shape[0]
    num_indices1 = indices1.shape[1]
    num_indices2 = indices2.shape[1]
    assert num_indices1 == coeffs1.shape[0]
    assert num_indices2 == coeffs2.shape[0]
    assert num_vars == indices2.shape[0]

    indices_dict = dict()
    max_num_indices = num_indices1 * num_indices2
    indices = np.empty((num_vars, max_num_indices), int)
    coeffs = np.empty((max_num_indices), float)
    kk = 0
    for ii in range(num_indices1):
        index1 = indices1[:, ii]
        coeff1 = coeffs1[ii]
        for jj in range(num_indices2):
            index = index1 + indices2[:, jj]
            key = hash_array(index)
            coeff = coeff1 * coeffs2[jj]
            if key in indices_dict:
                coeffs[indices_dict[key]] += coeff
            else:
                indices_dict[key] = kk
                indices[:, kk] = index
                coeffs[kk] = coeff
                kk += 1
    indices = indices[:, :kk]
    coeffs = coeffs[:kk]
    return indices, coeffs
def group_like_terms(coeffs, indices):
    if coeffs.ndim == 1:
        coeffs = coeffs[:, np.newaxis]

    num_vars, num_indices = indices.shape
    indices_dict = {}
    for ii in range(num_indices):
        key = hash_array(indices[:, ii])
        if not key in indices_dict:
            indices_dict[key] = [coeffs[ii], ii]
        else:
            indices_dict[key] = [indices_dict[key][0] + coeffs[ii], ii]

    new_coeffs = np.empty((len(indices_dict), coeffs.shape[1]))
    new_indices = np.empty((num_vars, len(indices_dict)), dtype=int)
    ii = 0
    for key, item in indices_dict.items():
        new_indices[:, ii] = indices[:, item[1]]
        new_coeffs[ii] = item[0]
        ii += 1
    return new_coeffs, new_indices
def add_polynomials(indices_list, coeffs_list):
    """ 
    Add many polynomials together.

    Example:
        p1 = x1**2+x2+x3, p2 = x2**2+2*x3
        p3 = p1+p2 

       return the degrees of each term in the the polynomial 
       
       p3 = x1**2+x2+3*x3+x2**2
      
       [2, 1, 1, 2]

       and the coefficients of each of these terms

       [1., 1., 3., 1.]
       

    Parameters
    ----------
    indices_list : list [np.ndarray (num_vars,num_indices_i)]
        List of polynomial indices. indices_i may be different for each 
        polynomial

    coeffs_list : list [np.ndarray (num_indices_i,num_qoi)]
        List of polynomial coefficients. indices_i may be different for each 
        polynomial. num_qoi must be the same for each list element.


    Returns
    -------
    indices: np.ndarray (num_vars,num_terms)
        the polynomial indices of the polynomial obtained from
        summing the polynomials. This will be the union of the indices
        of the input polynomials

    coeffs: np.ndarray (num_terms,num_qoi)
        the polynomial coefficients of the polynomial obtained from
        summing the polynomials
    """

    num_polynomials = len(indices_list)
    assert num_polynomials == len(coeffs_list)
    indices_dict = dict()

    indices = []
    coeff = []
    ii = 0
    kk = 0
    for jj in range(indices_list[ii].shape[1]):
        assert coeffs_list[ii].ndim == 2
        assert coeffs_list[ii].shape[0] == indices_list[ii].shape[1]
        index = indices_list[ii][:, jj]
        indices_dict[hash_array(index)] = kk
        indices.append(index)
        coeff.append(coeffs_list[ii][jj, :].copy())
        kk += 1

    for ii in range(1, num_polynomials):
        #print indices_list[ii].T,num_polynomials
        assert coeffs_list[ii].ndim == 2
        assert coeffs_list[ii].shape[0] == indices_list[ii].shape[1]
        for jj in range(indices_list[ii].shape[1]):
            index = indices_list[ii][:, jj]
            key = hash_array(index)
            if key in indices_dict:
                nn = indices_dict[key]
                coeff[nn] += coeffs_list[ii][jj, :]
            else:
                indices_dict[key] = kk
                indices.append(index)
                coeff.append(coeffs_list[ii][jj, :].copy())
                kk += 1

    indices = np.asarray(indices).T
    coeff = np.asarray(coeff)

    return indices, coeff