Esempio n. 1
0
    def pad(obj1, obj2):
        if len(obj1.coefs) > len(obj2.coefs):
            obj2.coefs = np.append(
                obj2.coefs, (zeros_gm(len(obj1.coefs) - len(obj2.coefs), 1)))
        elif len(obj1.coefs) < len(obj2.coefs):
            obj1.coefs = np.append(
                obj1.coefs, (zeros_gm(len(obj2.coefs) - len(obj1.coefs), 1)))
        arr1 = obj1.coefs
        arr2 = obj2.coefs

        return arr1, arr2
Esempio n. 2
0
    def __init__(self, coefs, j, k, lam=np.array([1])):
        '''
        Constructor for Polynomial.

        Args:
            coefs: np.array of coefficients of the polynomial in terms of 
                the monomial basis P_jk. (Note: the basis is ordered 
                {P_01, P_02, P_03, P_11, P_12, P_13, ...}).
            j: degree of polynomial. If the length of coefs does not 
                equal 3*j + 3, zeros are added to the end of coefs.
            k: family of polynomial. Since most of the polynomials we 
                will deal with will come only from a certain family 
                (k = 1, 2, or 3), setting the k value will allow us to 
                deal with only the basis {P_0k, P_1k, ...}.
            lam: np.array of lambda_values used for calculating inner 
                products. If lam contains only one value, it is set as 
                a scalar. The default value is 1 (corresponding to the 
                regular Sobolev inner product).
        '''
        if not len(coefs) == 3 * j + 3:
            ad = zeros_gm(3 * j + 3 - len(coefs), 1)
            coefs = np.append(coefs, ad)
        self.coefs = coefs
        self.j = j
        self.k = k
        if len(lam) == 1:
            lam = lam[0]
        self.lam = lam
Esempio n. 3
0
    def build_condensed_GM(n, i, lam=np.array([1])):
        '''
        When we work with only polynomials from a certain family 
            (k = 1, 2, or 3), it is more convenient to only work with 
            the basis {P_0k, P_1k,...}. This function creates the 
            Gram Matrix for a given generalized Sobolev inner product.

        Args:
            n: size of Gram Matrix required
            i: family of polynomials (i represents k in the preceding 
                paragraph)
            lam: np.array of lambda values for the generalized Sobolev 
                inner product. The default value is 1 (corresponding to 
                the regular Sobolev inner product).
                If lam = np.array([0]), this is the L2 inner product.
        '''
        if Polynomial.has_GM(3 * n + 3, lam):
            return

        arr = zeros_gm(n, n)
        if not (np.array_equal(lam, np.array([1])) \
                or np.array_equal(lam, np.array([0]))):
            lam_arr = [np.array([1]), np.array([0]), lam]
        else:
            lam_arr = [np.array([1]), np.array([0])]
        for lamb in lam_arr:
            for ind1 in tqdm.tqdm(range(n), file=sys.stdout):
                for ind2 in range(n):
                    if ind1 <= ind2:
                        arr[ind1, ind2] = \
                            Polynomial.basis_inner(ind1, i, ind2, i, lamb)

            Polynomial.GM[lis2str(lamb)] = symmetrize(arr)
Esempio n. 4
0
    def build_GM(n, lam=np.array([1])):
        '''
        Constructs Gram Matrix of a given size for a given generalized 
            Sobolev inner product. This is used to later compute inner 
            products more quickly.
        The Gram Matrix is stored in the dictionary Polynomial.GM keyed 
            by the string representing the values of lambda.

        Args:
            n: size of Gram Matrix
            lam: np.array of lambda values for the generalized Sobolev 
                inner product. The default value is 1 (corresponding to 
                the regular Sobolev inner product).
                If lam = np.array([0]), this is the L2 inner product.
        '''
        if Polynomial.has_GM(3 * n + 3, lam):
            return

        arr = zeros_gm(3 * n + 3, 3 * n + 3)
        #The following if else statements make an array lam_arr that represents the weights of all the integrals
        # in the inner product formula. This is required because lam only describes the weights on the integrals with positive order laplacians because
        # integrals with positive order laplacians as we consider the weight on the L2 inner product to be 1.

        if not (np.array_equal(lam, np.array([1])) \
                or np.array_equal(lam, np.array([0]))):
            lam_arr = [np.array([1]), np.array([0]), lam]
        else:
            lam_arr = [np.array([1]), np.array([0])]

        for lamb in lam_arr:
            for ind1 in range(n):
                for ind2 in range(n):
                    if ind1 <= ind2:
                        j = int(np.floor(ind1 / 3))
                        k = int(np.floor(ind2 / 3))
                        i = int(ind1 % 3 + 1)
                        ip = int(ind2 % 3 + 1)
                        arr[ind1, ind2] = \
                            Polynomial.basis_inner(j, i, k, ip, lamb)
            Polynomial.GM[lis2str(lamb)] = symmetrize(arr)

        return
Esempio n. 5
0
def generate_symm_ops(n, normalized=False, lam=np.array([1]), frac=True):
    '''
    Generates symmetric orthogonal polynomials with respect to a 
        generalized Sobolev inner product. The Gram-Schmidt algorithm 
        is implemented here.

    Args:
        n: Maximum degree of orthogonal polynomial.
        normalized: Boolean representing whether the resulting polynomials 
            should be normalized or monic.
        lam: np.array of lambda values for the generalized Sobolev inner 
            product. The default value is 1 (corresponding to the regular 
            Sobolev inner product). If lam = np.array([0]), 
            this is the L2 inner product.
        frac: Boolean representing whether the coefficients should remain 
            as fractions or should be converted to floating point numbers 
            at the end of all calculations.

    Returns:
        np.array of coefficients of the orthogonal polynomials with 
            respect to the basis {R_0, R_1, ..., R_j}. Each row in 
            this array is a polynomial, and there are n+1 rows and n+1 
            columns.
            If normalized is True, the polynomials will be normalized.
            Otherwise, the polynomials will be monic. If normalized 
            is True, frac must be False to obtain normalized coefficients.
    
    '''

    print('Building Gram Matrix ... this may take some time')
    SGM = zeros_gm(n + 1, n + 1)

    for ind1 in range(n + 1):
        for ind2 in range(n + 1):
            if ind1 <= ind2:
                SGM[ind1, ind2] = inner_rjrk(ind1, ind2, lam)

    SGM = symmetrize(SGM)

    basis_mat = eye_gm(n + 1)
    o_basis_mat = zeros_gm(n + 1, n + 1)

    o_basis_mat[0] = basis_mat[0]

    print('Orthogonalizing Using Gram-Schmidt')
    for r in tqdm.tqdm(range(1, n + 1)):
        u_r = basis_mat[r]
        for i in range(r):
            v_i = o_basis_mat[i]

            proj = Polynomial.fast_inner(u_r, v_i, SGM)
            norm = Polynomial.fast_inner(v_i, v_i, SGM)
            u_r -= (proj / norm) * v_i
        o_basis_mat[r] = u_r

    if frac and normalized:
        print(
            'Normalization requires conversion to float. Please set frac = False.'
        )
        print('Generating non-normalized coefficients now...')
    if not frac:
        if normalized:
            o_basis_arr = np.zeros((n + 1, n + 1))
            print('Normalizing')
            for i in tqdm.tqdm(range(n + 1)):
                norm = Polynomial.fast_inner(o_basis_mat[i], o_basis_mat[i],
                                             SGM)
                o_basis_arr[i] = o_basis_mat[i] / gm.sqrt(norm)
            return o_basis_arr
        return np.array(o_basis_mat, dtype=np.float64)

    return o_basis_mat
Esempio n. 6
0
def leg_ops_recursion(j, k, normalized=False, frac=True, return_f=False):
    '''
        This function uses the three term recursion from the Kasso Tuley paper to generate the first j
        Legendre orthogonal polynomials.

        Args:
            j: maximum degree of polynomials
            k: family of monomials to use in the construction of the orthogonal polynomials 
                (only k = 2,3 supported currently)
            normalized: Boolean representing whether the resulting polynomials 
                should be normalized or monic.
            frac: Boolean representing whether the coefficients should remain as fractions or should be
                converted to floating point numbers at the end of all calculations
            return_f: Boolean representing whether the f polynomials should also be returned

        Returns:
            np.array of coefficients of the Legendre orthogonal polynomials with 
                respect to the basis {P_0k, P_1k,..., P_jk}. Each row in 
                this array is a polynomial, and there are j+1 rows and j+1 
                columns. If normalized is True, the polynomials will be normalized. 
                Otherwise, the polynomials will be monic. If normalized is True, frac must be False
                to obtain normalized coefficients. If return_f is True, a tuple containing the Legendre 
                coefficients and the f polynomial coefficients is returned.
    '''

    if k == 1:
        print('This method is currently only proven for k = 2 or 3.')

    # this is so the indices match

    if return_f: f_mat = np.empty((j + 1, j + 1), dtype=object)

    o_basis_mat = np.empty((j + 1, j + 1), dtype=object)
    print(
        'Using Gram-Schmidt to get the initial Legendre polynomials for recursion'
    )
    with HiddenPrints():
        first_mat = generate_op_GS(1,
                                   k,
                                   normalized=False,
                                   lam=np.array([0]),
                                   frac=frac)
    const = gm.mpz(0) if frac else 0
    first_mat = np.pad(first_mat, ((0, 0), (0, j - 1)),
                       'constant',
                       constant_values=(const, ))
    o_basis_mat[:2] = first_mat

    if k == 3: func_array = gamma_array
    if k == 2: func_array = beta_array
    if k == 1: func_array = alpha_array

    print('Generating values for f_n')
    func_arr = func_array(j + 2)
    print('Building Gram Matrix for inner product caluclation.')
    Polynomial.build_condensed_GM(j + 1, k, np.array([0]))
    GM = Polynomial.GM[lis2str(np.array([0]))][:j + 1, :j + 1]

    print('Using recursion to generate the rest of the Legendre Poynomials')

    if return_f:
        f_mat[0] = zeros_gm(1, f_mat.shape[1])
        func_vec = func_arr[1:2]
        omega_vec = o_basis_mat[0, :1]
        zeta_ind = gm.mpq(-1, func_arr[0]) * func_vec.dot(omega_vec)
        f_ind = np.insert(omega_vec, 0, zeta_ind)
        f_mat[1] = np.pad(f_ind, (0, j - 1),
                          'constant',
                          constant_values=(const, ))

    for ind in tqdm.tqdm(range(1, j), file=sys.stdout):
        func_vec = func_arr[1:ind + 2]
        omega_vec = o_basis_mat[ind, :ind + 1]
        zeta_ind = gm.mpq(-1, func_arr[0]) * func_vec.dot(omega_vec)
        f_ind = np.insert(omega_vec, 0, zeta_ind)
        d_ind2 = gm.mpq(
            1,
            Polynomial.fast_inner(o_basis_mat[ind, :ind + 1],
                                  o_basis_mat[ind, :ind + 1],
                                  GM[:ind + 1, :ind + 1]))
        d_indm2 = gm.mpq(
            1,
            Polynomial.fast_inner(o_basis_mat[ind - 1, :ind],
                                  o_basis_mat[ind - 1, :ind], GM[:ind, :ind]))
        b_ind = d_ind2 * Polynomial.fast_inner(
            f_ind, o_basis_mat[ind, :ind + 2], GM[:ind + 2, :ind + 2])
        c_ind = gm.mpq(d_indm2, d_ind2)

        new_vec = f_ind - b_ind * o_basis_mat[
            ind, :ind + 2] - c_ind * o_basis_mat[ind - 1, :ind + 2]

        o_basis_mat[ind + 1] = np.pad(new_vec, (0, j - ind - 1),
                                      'constant',
                                      constant_values=(const, ))
        if return_f:
            f_mat[ind + 1] = np.pad(f_ind, (0, j - ind - 1),
                                    'constant',
                                    constant_values=(const, ))

    if frac and normalized:
        print(
            'Normalization requires conversion to float. Please set frac = False.'
        )
        print('Generating non-normalized coefficients now...')
    if not frac:
        if normalized:
            o_basis_arr = np.zeros((j + 1, j + 1))
            print('Normalizing')
            for i in tqdm.tqdm(range(j + 1), file=sys.stdout):
                norm = Polynomial.fast_inner(o_basis_mat[i], o_basis_mat[i],
                                             GM)
                o_basis_arr[i] = o_basis_mat[i] / gm.sqrt(norm)
            return (o_basis_arr, np.array(
                f_mat, dtype=np.float64)) if return_f else o_basis_arr
        return (np.array(o_basis_mat, dtype=np.float64),
                np.array(f_mat, dtype=np.float64)) if return_f else np.array(
                    o_basis_mat, dtype=np.float64)

    return (o_basis_mat, f_mat) if return_f else o_basis_mat
Esempio n. 7
0
def generate_op_GS(n, k, normalized=False, lam=np.array([1]), frac=True):
    '''
    Generates orthogonal polynomials with respect to a generalized Sobolev 
        inner product. The Gram-Schmidt algorithm is implemented here.

    Args:
        n: Maximum degree of orthogonal polynomial.
        k: family of monomials to use in Gram-Schmidt (k = 1, 2, or 3)
        normalized: Boolean representing whether the resulting polynomials 
            should be normalized or monic.
        lam: np.array of lambda values for the generalized Sobolev inner 
            product. The default value is 1 (corresponding to the regular 
            Sobolev inner product). If lam = np.array([0]), 
            this is the L2 inner product.
        frac: Boolean representing whether the coefficients should remain as fractions or should be
        converted to floating point numbers at the end of all calculations.

    Returns:
        np.array of coefficients of the orthogonal polynomials with 
            respect to the basis {P_0k, P_1k,..., P_nk}. Each row in 
            this array is a polynomial, and there are n+1 rows and n+1 
            columns.
            If normalized is True, the polynomials will be normalized. 
            Otherwise, the polynomials will be monic. If normalized is True, frac must be False
            to obtain normalized coefficients.
    
    '''

    print('Building Gram Matrix ... this may take some time')
    Polynomial.build_condensed_GM(n + 1, k, lam)

    basis_mat = eye_gm(n + 1)
    o_basis_mat = zeros_gm(n + 1, n + 1)

    o_basis_mat[0] = basis_mat[0]
    GM = Polynomial.GM[lis2str(lam)][:n + 1, :n + 1]
    print('Orthogonalizing Using Gram-Schmidt')
    for r in tqdm.tqdm(range(1, n + 1), file=sys.stdout):

        u_r = basis_mat[r]
        for i in range(r):
            v_i = o_basis_mat[i]

            proj = Polynomial.fast_inner(u_r, v_i, GM)
            norm = Polynomial.fast_inner(v_i, v_i, GM)
            u_r -= (proj / norm) * v_i
        o_basis_mat[r] = u_r
    if frac and normalized:
        print(
            'Normalization requires conversion to float. Please set frac = False.'
        )
        print('Generating non-normalized coefficients now...')
    if not frac:
        if normalized:
            o_basis_arr = np.zeros((n + 1, n + 1))
            print('Normalizing')
            for i in tqdm.tqdm(range(n + 1), file=sys.stdout):
                norm = Polynomial.fast_inner(o_basis_mat[i], o_basis_mat[i],
                                             GM)
                o_basis_arr[i] = o_basis_mat[i] / gm.sqrt(norm)
            return o_basis_arr
        return np.array(o_basis_mat, dtype=np.float64)

    return o_basis_mat
Esempio n. 8
0
def big_recursion(j):
    '''
    This function computes the coefficients a_j, b_j, p_j, q_j found in 
        the Splines on Fractals paper.

    Args:
        j: index of coefficients

    Returns:
        4 x j+1 np.array of coefficients a_j, b_j, p_j, q_j from 0 to j
    '''
    # Initialize space for the coefficients
    p_arr = zeros_gm(j + 1, 1)
    q_arr = zeros_gm(j + 1, 1)
    a_arr = zeros_gm(j + 1, 1)
    b_arr = zeros_gm(j + 1, 1)

    # Initialize arrays for the 0-th term
    a_arr[0] = gm.mpq(7, 45)
    b_arr[0] = gm.mpq(4, 45)
    p_arr[0] = gm.mpq(2, 5)
    q_arr[0] = gm.mpq(1, 5)

    if j == 0:
        return np.vstack((a_arr, b_arr, p_arr, q_arr))

    # Main recursion
    for l in range(1, j + 1):
        # Implements equation (5.6) in Splines paper
        res3 = 0
        res4 = 0
        for k in range(l):
            p = p_arr[k]
            q = q_arr[k]
            a = a_arr[l - k - 1]
            b = b_arr[l - k - 1]
            res3 += (4 * a + 3 * b) * p + (a + 2 * b) * q
            res4 += (2 * a + 4 * b) * p + (3 * a + b) * q

        b = b_arr[l - 1]
        p_arr[l] = -gm.mpq(2, 5) * b - gm.mpq(1, 5) * res3
        q_arr[l] = -gm.mpq(1, 5) * b - gm.mpq(1, 5) * res4

        # Implements equation (5.5) in Splines paper
        res1 = 0
        res2 = 0
        vec = zeros_gm(2, 1)
        for k in range(l):
            p = p_arr[l - k]
            q = q_arr[l - k]
            a = a_arr[k]
            b = b_arr[k]
            res1 += (2 * p + q) * (a + 2 * b)
            res2 += (p + 2 * q) * (a + 2 * b)

        vec[0] = gm.mpq(2, (3 * (5**l - 1))) * res1
        vec[1] = gm.mpq(10, (3 * (5**(l + 1) - 1))) * res2
        coefs_inv = np.array([[gm.mpq(7, 15), gm.mpq(-2, 15)],
                              [gm.mpq(4, 15), gm.mpq(1, 15)]])
        ab_arr = coefs_inv.dot(vec)
        a_arr[l] = ab_arr[0]
        b_arr[l] = ab_arr[1]

    return np.vstack((a_arr.T, b_arr.T, p_arr.T, q_arr.T))