def Nystrom(k):
    r"""
    Construct the k-step explicit Nystrom linear multistep method.
    The methods are explicit and have order k.
    They have the form:

    `y_{n+1} = y_{n-1} + h \sum_{j=0}^{k-1} \beta_j f(y_n-k+j+1)`

    They are generated using equations (1.13) and (1.7) from 
    [hairer1993]_ III.1, along with the binomial expansion
    and the relation in exercise 4 on p. 367.

    Note that the term "Nystrom method" is also commonly used to refer
    to a class of methods for second-order ODEs; those are NOT
    the methods generated by this function.

    **Examples**::

        >>> import linear_multistep_method as lm
        >>> nys3=lm.Nystrom(6)
        >>> nys3.order()
        6

        References:
            #. [hairer1993]_
    """
    import sympy
    from sympy import Rational

    one = Rational(1,1)

    alpha = snp.zeros(k+1)
    alpha[k] = one
    alpha[k-2] = -one

    beta  = snp.zeros(k+1)
    kappa = snp.zeros(k)
    gamma = snp.zeros(k)
    gamma[0]  =   one
    kappa[0]  = 2*one
    beta[k-1] = 2*one
    betaj = snp.zeros(k+1)
    for j in range(1,k):
        gamma[j] = one-sum(gamma[:j]/snp.arange(j+1,1,-1))
        kappa[j] = 2 * gamma[j] - gamma[j-1]
        for i in range(0,j+1):
            betaj[k-i-1] = (-one)**i*sympy.combinatorial.factorials.binomial(j,i)*kappa[j]
        beta = beta+betaj
    name = str(k)+'-step Nystrom'
    return LinearMultistepMethod(alpha,beta,name=name,shortname='Nys'+str(k))
def Milne_Simpson(k):
    r"""
        Construct the k-step, Milne-Simpson method.
        The methods are implicit and (for k>=3) have order k+1.
        They have the form:

        `y_{n+1} = y_{n-1} + h \sum_{j=0}^{k} \beta_j f(y_n-k+j+1)`

        They are generated using equation (1.15), the equation in 
        Exercise 3, and the relation in exercise 4, all from Hairer & Wanner
        III.1, along with the binomial expansion.

        **Examples**::

            >>> import linear_multistep_method as lm
            >>> ms3=lm.Milne_Simpson(3)
            >>> ms3.order()
            4

        References:
            [hairer1993]_
    """
    import sympy

    alpha = snp.zeros(k+1)
    beta  = snp.zeros(k+1)
    alpha[k] = 1
    alpha[k-2] = -1
    gamma = snp.zeros(k+1)
    kappa = snp.zeros(k+1)
    gamma[0] = 1
    kappa[0] = 2
    beta[k]  = 2
    betaj = snp.zeros(k+1)
    for j in range(1,k+1):
        gamma[j] = -sum(gamma[:j]/snp.arange(j+1,1,-1))
        kappa[j] = 2 * gamma[j] - gamma[j-1]
        for i in range(0,j+1):
            betaj[k-i] = (-1)**i*sympy.combinatorial.factorials.binomial(j,i)*kappa[j]
        beta = beta+betaj
    name = str(k)+'-step Milne-Simpson'
    return LinearMultistepMethod(alpha,beta,name=name,shortname='MS'+str(k))
Beispiel #3
0
def Adams_Bashforth(k):
    r""" 
    Construct the k-step, Adams-Bashforth method.
    The methods are explicit and have order k.
    They have the form:

    `y_{n+1} = y_n + h \sum_{j=0}^{k-1} \beta_j f(y_n-k+j+1)`

    They are generated using equations (1.5) and (1.7) from 
    [hairer1993]_ III.1, along with the binomial expansion.

    **Examples**::

        >>> import linear_multistep_method as lm
        >>> ab3=lm.Adams_Bashforth(3)
        >>> ab3.order()
        3

        References:
            #. [hairer1993]_
    """
    import sympy
    from sympy import Rational

    one = Rational(1,1)

    alpha=snp.zeros(k+1)
    beta=snp.zeros(k+1)
    alpha[k]=one
    alpha[k-1]=-one
    gamma=snp.zeros(k)
    gamma[0]=one
    beta[k-1]=one
    betaj=snp.zeros(k+1)
    for j in range(1,k):
        gamma[j]=one-sum(gamma[:j]/snp.arange(j+1,1,-1))
        for i in range(0,j+1):
            betaj[k-i-1]=(-one)**i*sympy.combinatorial.factorials.binomial(j,i)*gamma[j]
        beta=beta+betaj
    name=str(k)+'-step Adams-Bashforth method'
    return LinearMultistepMethod(alpha,beta,name=name)
def sand_cc(s):
    r""" Construct Sand's circle-contractive method of order `p=2(s+1)`
         that uses `2^s + 1` steps.

    **Examples**::

        >>> import linear_multistep_method as lm
        >>> cc4 = lm.sand_cc(4)
        >>> cc4.order()
        10
        >>> cc4.ssp_coefficient()
        1/8

    **References**:
        #. [sand1986]_
    """
    import sympy

    one  = sympy.Rational(1)
    zero = sympy.Rational(0)

    k = 2**s + 1
    p = 2*(s+1)

    Jn = [k,k-1]
    for i in range(1,s+1):
        Jn.append(k-1-2**i)

    alpha = snp.zeros(k+1)
    beta  = snp.zeros(k+1)

    # This is inefficient
    for j in Jn:
        tau_product = one
        tau_sum = zero
        tau = [one/(j-i) for i in Jn if i!=j]
        tau_product = np.prod(tau)
        tau_sum = np.sum(tau)
        beta[j] = tau_product**2
        alpha[j] = 2*beta[j]*tau_sum
    return LinearMultistepMethod(alpha,beta,'Sand circle-contractive')
Beispiel #5
0
def elm_ssp2(k):
    r"""
    Returns the optimal SSP k-step linear multistep method of order 2.

    **Examples**::

        >>> import linear_multistep_method as lm
        >>> lm10=lm.elm_ssp2(10)
        >>> lm10.ssp_coefficient()
        8/9
    """
    import sympy

    alpha=snp.zeros(k+1)
    beta=snp.zeros(k+1)
    alpha[-1]=sympy.Rational(1,1)
    alpha[0]=sympy.Rational(-1,(k-1)**2)
    alpha[k-1]=sympy.Rational(-(k-1)**2+1,(k-1)**2)
    beta[k-1]=sympy.Rational(k,k-1)
    name='Optimal '+str(k)+'-step, 2nd order SSP method.'
    return LinearMultistepMethod(alpha,beta,name=name)
Beispiel #6
0
def sand_cc(s):
    r""" Construct Sand's circle-contractive method of order `p=2(s+1)`.

    **Examples**::

        >>> import linear_multistep_method as lm
        >>> cc4 = lm.sand_cc(4)
        >>> cc4.order()
        10
        >>> cc4.ssp_coefficient()
        1/8

    **References**:
        #. [sand1986]_
    """
    import sympy

    one  = sympy.Rational(1)
    zero = sympy.Rational(0)

    k = 2**s + 1
    p = 2*(s+1)

    Jn = [k,k-1]
    for i in range(1,s+1):
        Jn.append(k-1-2**i)

    alpha = snp.zeros(k+1)
    beta  = snp.zeros(k+1)

    # This is inefficient
    for j in Jn:
        tau_product = one
        tau_sum = zero
        tau = [one/(j-i) for i in Jn if i!=j]
        tau_product = np.prod(tau)
        tau_sum = np.sum(tau)
        beta[j] = tau_product**2
        alpha[j] = 2*beta[j]*tau_sum
    return LinearMultistepMethod(alpha,beta,'Sand circle-contractive')
Beispiel #7
0
def Adams_Moulton(k):
    r""" 
        Construct the k-step, Adams-Moulton method.
        The methods are implicit and have order k+1.
        They have the form:

        `y_{n+1} = y_n + h \sum_{j=0}^{k} \beta_j f(y_n-k+j+1)`

        They are generated using equation (1.9) and the equation in 
        Exercise 3 from Hairer & Wanner III.1, along with the binomial 
        expansion.

        **Examples**::

            >>> import linear_multistep_method as lm
            >>> am3=lm.Adams_Moulton(3)
            >>> am3.order()
            4

        References:
            [hairer1993]_
    """
    import sympy

    alpha=snp.zeros(k+1)
    beta=snp.zeros(k+1)
    alpha[k]=1
    alpha[k-1]=-1
    gamma=snp.zeros(k+1)
    gamma[0]=1
    beta[k]=1
    betaj=snp.zeros(k+1)
    for j in range(1,k+1):
        gamma[j]= -sum(gamma[:j]/snp.arange(j+1,1,-1))
        for i in range(0,j+1):
            betaj[k-i]=(-1)**i*sympy.combinatorial.factorials.binomial(j,i)*gamma[j]
            #betaj[k-i]=(-1.)**i*comb(j,i)*gamma[j]
        beta=beta+betaj
    name=str(k)+'-step Adams-Moulton method'
    return LinearMultistepMethod(alpha,beta,name=name)
Beispiel #8
0
def backward_difference_formula(k):
    r""" 
        Construct the k-step backward differentiation method.
        The methods are implicit and have order k.
        They have the form:

        `\sum_{j=0}^{k} \alpha_j y_{n+k-j+1} = h \beta_j f(y_{n+1})`

        They are generated using equation (1.22') from Hairer & Wanner III.1,
            along with the binomial expansion.

        **Examples**::

            >>> import linear_multistep_method as lm
            >>> bdf4=lm.backward_difference_formula(4)
            >>> bdf4.A_alpha_stability()
            146

        **References**:
            #.[hairer1993]_ pp. 364-365
    """
    import sympy

    alpha=snp.zeros(k+1)
    beta=snp.zeros(k+1)
    beta[k]=1
    gamma=snp.zeros(k+1)
    gamma[0]=1
    alphaj=snp.zeros(k+1)
    for j in range(1,k+1):
        gamma[j]= sympy.Rational(1,j)
        for i in range(0,j+1):
            alphaj[k-i]=(-1)**i*sympy.combinatorial.factorials.binomial(j,i)*gamma[j]
        alpha=alpha+alphaj
    name=str(k)+'-step BDF method'
    return LinearMultistepMethod(alpha,beta,name=name)
    def stability_matrix(self,z):
        r""" 
            Constructs the stability matrix of a two-step Runge-Kutta method.
            Right now just for a specific value of z.
            We ought to use Sage to do it symbolically.

            **Output**:
                M -- stability matrix evaluated at z

            WARNING: This only works for Type I & Type II methods
            right now!!!
        """
        s = self.Ahat.shape[1]
        if self.type == 'General':
            # J Y^n = K Y^{n-1}
            K1 = np.column_stack((z*self.Ahat,self.d,1-self.d))
            K2 = snp.zeros(s+2); K2[-1] = 1
            K3 = np.concatenate((z*self.bhat,np.array((self.theta,1-self.theta))))
            K = np.vstack((K1,K2,K3))

            J = snp.eye(s+2)
            J[:s,:s] = J[:s,:s] - z*self.A
            J[-1,:s] = z*self.b

            M = snp.solve(J.astype('complex64'),K.astype('complex64'))
            #M = snp.solve(J, K) # This version is slower

        else:
            D=np.hstack([1.-self.d,self.d])
            thet=np.hstack([1.-self.theta,self.theta])
            A,b=self.A,self.b
            if self.type=='Type II':
                ahat = np.zeros([self.s,1]); ahat[:,0] = self.Ahat[:,0]
                bh = np.zeros([1,1]); bh[0,0]=self.bhat[0]
                A = np.hstack([ahat,self.A])
                A = np.vstack([np.zeros([1,self.s+1]),A])
                b =  np.vstack([bh,self.b])

            M1=np.linalg.solve(np.eye(self.s)-z*self.A,D)
            L1=thet+z*np.dot(self.b.T,M1)
            M=np.vstack([L1,[1.,0.]])
        return M