Esempio n. 1
0
def thetas_alphas(rat_func, prec, *, use_intervals=False, eps=None):
    """
    Do a partial fraction decomposition of rat_func

    Returns (thetas, alphas, alpha0), where thetas and alphas are lists of
    values such that

        rat_func = alpha0 + sum([alpha/(t - theta) for theta,
            alpha in zip(thetas, alphas)])

    The thetas and alphas are in general complex numbers.

    Assumes that rat_func has the same degree numerator as denominator.

    If use_intervals=True, this uses the intevals() algorithm to do root
    finding. This algorithm is very slow, but has guaranteed precision, and is
    guaranteed to find all the roots. If it is False (the default), nsolve is
    used.

    eps is the length of the intervals for root finding. By default it is set
    to 10**-prec but it may need to be set smaller if there are roots smaller
    than ~1/10 to get full precision. If use_intervals=False, eps is ignored.
    """
    import mpmath
    mpmath.mp.dps = prec

    num, den = fraction(rat_func)
    d = degree(den)

    if use_intervals:
        rational_rat_func = nsimplify(rat_func)
        num, den = fraction(rational_rat_func)

        if d % 1:
            raise NotImplementedError("Odd degrees are not yet supported with use_intervals=True")

        # Note, eps is NOT the precision. It's the length of the interval.
        # If a root is small (say, on the order of 10**-N), then eps will need to be 10**(-N - d)
        # to get d digits of precision. For our exp(-t) approximations, the roots
        # (thetas) are all
        # within order 10**-1...10**1, so eps is *roughly* the precision.
        eps = eps or 10**-prec

        roots = intervals(den, all=True, eps=eps)[1]
        # eps ought to be small enough that either side of the interval is the
        # precision we want, but take the average (center of the rectangle)
        # anyway.
        # XXX: Make sure to change the evalf precision if eps is lowered.
        thetas = [((i + j)/2).evalf(prec) for ((i, j), _) in roots]
        # error = [(j - i).evalf(prec) for ((i, j), _) in roots]
    else:
        thetas = list(allroots(den, d, prec))
    alphas = []
    for theta in thetas:
        q, r = div(den, t - theta)
        alpha = (num/q).evalf(prec, subs={t: theta})
        alphas.append(alpha)
    alpha0 = (LC(num)/LC(den)).evalf(prec)
    return thetas, alphas, alpha0
Esempio n. 2
0
def find_gh(d, s, r, z):
    f0 = ffx(d, s, z)
    fr = f0.subs(z, z - r)
    g, _h, one = gcdex(f0, fr)
    h = -_h
    assert one == 1

    if not g.is_number:
        assert LC(g) > 0
        assert LC(h) > 0
    else:
        assert g > 0

    return g, h
Esempio n. 3
0
def split_affine(expr):
    """
    Split an affine scalar function into its three components, namely variable,
    coefficient, and translation from origin.

    Raises
    ------
    ValueError
        If ``expr`` is non affine.
    """
    if expr.is_Number:
        return AffineFunction(None, None, expr)

    # Handle super-quickly the calls like `split_affine(x+1)`, which are
    # the majority.
    if expr.is_Add and len(expr.args) == 2:
        if expr.args[0].is_Number and expr.args[1].is_Symbol:
            # SymPy deterministically orders arguments -- first numbers, then symbols
            return AffineFunction(expr.args[1], 1, expr.args[0])

    # Fallback
    poly = expr.as_poly()
    if not (poly.is_univariate and poly.is_linear) or not LM(poly).is_Symbol:
        raise ValueError
    return AffineFunction(LM(poly), LC(poly), poly.TC())
Esempio n. 4
0
def LMQ(f):
    """
    Local Max Quadratic
    """
    g = f if LC(f) > 0 else -f
    F = list(reversed(Poly(g).all_coeffs()))
    N, temp_max = len(F), 0
    if N <= 1: return None
    times_used = [1] * N
    for m in range(N - 1, 0, -1):
        if F[m - 1] < 0:
            index = 0
            temp_min = S("oo")
            for n in range(N, m, -1):
                if F[n - 1] > 0:
                    q = ((2.0**times_used[n - 1]) *
                         (-F[m - 1] / F[n - 1]))**(1.0 / (n - m))
                    if q < temp_min:
                        temp_min = q
                        index = n - 1
            times_used[index] = times_used[index] + 1
            #            print times_used
            if temp_max < temp_min:
                temp_max = temp_min


#    print  temp_max    ,  times_used
    return ceiling((65.0 / 64) * (temp_max))
Esempio n. 5
0
def PSC(F, G, x):
    """PSC(F, G, x) returns a set with the non-zero principal subresultant
    coefficients (psc) of the two polynomials F and G with respect to the
    variable x.
    
    If the degree of the polynomial F is strictly less than the degree of
    the polynomial G, then F and G are interchanged.
    
    Extended psc beyond the n-th are not considered, where n is the minimum
    of the degrees of F and G with respect to x.

    >>> PSC(0, 0, var('x'))
    set()
    >>> PSC(poly('2*x'), poly('3*y'), var('x'))
    {3*y}
    >>> PSC(poly('2*x'), poly('3*y + 5*x**2'), var('x')) == {12*var('y'), 2}
    True
    >>> PSC(poly('x**3'), poly('x**3 + x'), var('x'))
    {1}
    """
    subs = subresultants(F, G, x)
    s = set()
    i = len(subs) - 1
    if i < 0:
        return s
    currDeg = degree(subs[i], x)
    while i > 0:
        nextDeg = degree(subs[i - 1], x)
        s.add(LC(subs[i], x)**(nextDeg - currDeg))
        currDeg = nextDeg
        i -= 1
    return s
def zero_upper_bound_of_positive_poly(poly):
    poly = Poly(poly.expand())
    cs = poly.all_coeffs()
    cs0 = abs(cs[0])
    assert cs[0] == LC(poly)
    height = max(map(abs, cs))
    upper = ceiling(two * height / cs0)
    upper = int(upper)
    assert upper >= 2
    return upper
Esempio n. 7
0
def split_affine(expr):
    """
    split_affine(expr)

    Split an affine scalar function into its three components, namely variable,
    coefficient, and translation from origin.

    :raises ValueError: If ``expr`` is non affine.
    """
    if expr.is_Number:
        return AffineFunction(None, None, expr)
    poly = expr.as_poly()
    if not (poly.is_univariate and poly.is_linear) or not LM(poly).is_Symbol:
        raise ValueError
    return AffineFunction(LM(poly), LC(poly), poly.TC())
Esempio n. 8
0
def CRAM_matrix_exp_lambdify(degree=14, prec=200, *, use_cache=True,
    form='complex partial fraction', py_solve=False):
    """
    Return a lambdified function for the CRAM approximation to exp(-x)

    form can be one of

    'complex partial fraction' (the default)
    'real partial fraction'
    'rational function'
    'rational function horner'
    'factored'

    When py_solve = True, the py_solve module will be used (scipy is used
    otherwise). In this case, it is much faster to pre-flatten the input
    matrix:

    >>> mat, time, b = ...
    >>> mat = py_solve.asflat(mat)
    >>> f = CRAM_matrix_exp_lambdify(py_solve=True)
    >>> f(-mat*time, b)

    """
    # TODO: This function should give exp(x), not exp(-x)

    if use_cache:
        rat_func = get_CRAM_from_cache(degree, prec)
    else:
        rat_func = CRAM_exp(degree, prec, plot=False)
    thetas, alphas, alpha0 = thetas_alphas(rat_func, prec)
    if form == 'complex partial fraction':
        expr = thetas_alphas_to_expr_complex(thetas, alphas, alpha0)
    elif form == 'real partial fraction':
        expr = thetas_alphas_to_expr_real(thetas, alphas, alpha0)
    elif form in ['rational function', 'rational function horner']:
        expr = rat_func
    elif form == 'factored':
        num, den = fraction(rat_func)
        # XXX: complex conjugate roots have the same absolute value
        numroots = sorted(allroots(num, degree, prec), key=lambda i: abs(i))
        denroots = sorted(allroots(den, degree, prec), key=lambda i: abs(i))
        p1q1 = LC(num)/LC(den)
    else:
        raise ValueError("Invalid argument for 'form': %s" % (form,))
    n0 = symbols("n0", commutative=False)

    if py_solve:
        from . import py_solve
        module = [py_solve, 'numpy']
        printer = MatrixNumPyPrinter({'py_solve': True})
        def wrapper(f):
            @wraps(f)
            def _f(t, n0):
                t = py_solve.asflat(t)
                return f(t, n0)
            return _f
    else:
        module = scipy_translations_autoeye
        printer = MatrixNumPyPrinter({'use_autoeye': True})
        wrapper = lambda f: f

    if form != 'factored':
        return wrapper(lambdify((t, n0), multiply_vector(expr, n0,
            horner=(form == 'rational function horner')),
            module, printer=printer, dummify=False))
    else:
        if py_solve:
            raise NotImplementedError("py_solve is not supported with factor yet")

        # TODO: Code generate this as a single expression
        def e_factored(mat, b, reverse=False):
            if reverse:
                r = reversed
            else:
                r = lambda i: i

            for num_root, den_root in zip(r(numroots), r(denroots)):
                f = lambdify((t, n0), multiply_vector((t - num_root)/(t -
                    den_root), n0), scipy_translations_autoeye,
                    printer=MatrixNumPyPrinter())
                b = f(mat, b)
            return float(p1q1)*b

        return e_factored
Esempio n. 9
0
    def _find_realization(self, G, s):
        """ Represenatation [A, B, C, D] of the state space model

        Returns the representation in state space of a given transfer function

        Parameters
        ==========

        G: Matrix
            Matrix valued transfer function G(s) in laplace space
        s: symbol
            variable s, where G is dependent from

        See Also
        ========

        Utils : some quick tools for matrix polynomials

        References
        ==========

        Joao P. Hespanha, Linear Systems Theory. 2009.
        """

        A, B, C, D = 4 * [None]

        try:
            m, k = G.shape

        except AttributeError:
            raise TypeError("G must be a matrix")

        # test if G is proper
        if not utl.is_proper(G, s, strict=False):
            raise ValueError("G must be proper!")

        # define D as the limit of G for s to infinity
        D = G.limit(s, oo)

        # define G_sp as the (stricly proper) difference of G and D
        G_sp = simplify(G - D)

        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
        # get the coefficients of the monic least common denominator of all entries of G_sp
        # compute a least common denominator using utl and lcm
        lcd = lcm(utl.fraction_list(G_sp, only_denoms=True))

        # make it monic
        lcd = simplify(lcd / LC(lcd, s))

        # and get a coefficient list of its monic. The [1:] cuts the LC away (thats a one)
        lcd_coeff = Poly(lcd, s).all_coeffs()[1:]

        # get the degree of the lcd
        lcd_deg = degree(lcd, s)

        # get the Matrix Valued Coeffs of G_sp in G_sp = 1/lcd * (N_1 * s**(n-1) + N_2 * s**(n-2) .. +N_n)
        G_sp_coeff = utl.matrix_coeff(simplify(G_sp * lcd), s)
        G_sp_coeff = [zeros(m, k)] * (lcd_deg - len(G_sp_coeff)) + G_sp_coeff

        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
        # now store A, B, C, D in terms of the coefficients of lcd and G_sp
        # define A
        A = (-1) * lcd_coeff[0] * eye(k)

        for alpha in lcd_coeff[1:]:
            A = A.row_join((-1) * alpha * eye(k))

        for i in xrange(lcd_deg - 1):
            if i == 0:
                tmp = eye(k)
            else:
                tmp = zeros(k)

            for j in range(lcd_deg)[1:]:
                if j == i:
                    tmp = tmp.row_join(eye(k))
                else:
                    tmp = tmp.row_join(zeros(k))
            if tmp is not None:
                A = A.col_join(tmp)

        # define B
        B = eye(k)
        for i in xrange(lcd_deg - 1):
            B = B.col_join(zeros(k))

        # define C
        C = G_sp_coeff[0]
        for i in range(lcd_deg)[1:]:
            C = C.row_join(G_sp_coeff[i])

        # return the state space representation
        return [simplify(A), simplify(B), simplify(C), simplify(D)]
def floor_div_nth_cf__nonzeroD(N_pair, D_pair, w_pair):
    '''D!=0, w>=0, return floor(N/D)

w_pow, w_nth = w_pair
assert w_pow >= 0, w_nth > 0
w = w_pow**(1/w_nth)

if D < 0: N, D = -N, -D
N_i, N_c = N_pair
D_i, D_c = D_pair
assert sign_nth_pair(D_pair, w_pair) > 0


assume Q = floor(N/D)
Q = max{int q | N >= q*D} >= 1
let N == q*D
(N_c - D_c*q)*w == -N_i + D_i*q
(N_c - D_c*q)**w_nth * w_pow == (-N_i + D_i*q)**w_nth
    (N_c - D_c*q)*w*nth_root(1,w_nth) == -N_i + D_i*q
    (N_c - D_c*q)*(+/-)w == -N_i + D_i*q or N_c - D_c*q == -N_i + D_i*q == 0
    q = N/D or (N_i-N_c*w)/(D_i-D_c*w) if [even w_nth] or N_c/D_c == N_i/D_i == N/D
    if N/D == (N_i-N_c*w)/(D_i-D_c*w) ==>>
        (N_i+N_c*w)*(D_i-D_c*w) == (N_i-N_c*w)*(D_i+D_c*w)
        (N_c*D_i - N_i*D_c)*w == 0
    len(real_roots(eq)) == 1 + [even w_nth][N_c*D_i != N_i*D_c]


'''

    w_pow, w_nth = w_pair
    assert w_pow >= 0, w_nth > 0

    #assert sign_nth_pair(D_pair, w_pair) > 0
    s = sign_nth_pair(D_pair, w_pair)
    if not s > 0:
        if s == 0:
            raise ValueError('D == 0')
        N_pair = neg_nth_pair(N_pair)
        D_pair = neg_nth_pair(D_pair)
    N_i, N_c = N_pair
    D_i, D_c = D_pair

    f = (N_c - D_c * _q)**w_nth * w_pow - (-N_i + D_i * _q)**w_nth
    f = f.expand()
    if LC(f) < 0:
        f = -f
    f = Poly(f)
    ##    upper = zero_upper_bound_of_positive_poly(f)
    ##    ndigit = num_radix_digits(upper, 2)
    ##    eps = (one/2**(ndigit+3))
    rngs = f.intervals()
    rngs = intervals(f)
    if len(rngs) == 2:
        assert w_nth & 1 == 0  # even
        assert N_i * D_c != N_c * D_i

        (low, up), m = rngs[0]
        # cmp(N, up*D) = cmp(N, a/b*D) = cmp(b*N, a*D)
        a, b = fraction(up)
        assert b > 0
        bN = times_nth_pair(b, N_pair)
        aD = times_nth_pair(a, D_pair)
        s = cmp_nth_pair(bN, aD)
        assert s
        if s < 0:
            # Q in rngs[0]
            del rngs[1]
        else:
            del rngs[0]

    assert len(rngs) == 1
    (low, up), m = rngs[0]
    Q = floor_bucketed_root(f, low, up)
    R_pair = sub_nth_pair(N_pair, times_nth_pair(Q, D_pair))
    ##    Q = int(floor(low))
    ##    R_pair = sub_nth_pair(N_pair, times_nth_pair(Q, D_pair))
    ##    if not cmp_nth_pair(R_pair, D_pair, w_pair) < 0:
    ##        Q += 1
    ##        R_pair = sub_nth_pair(R_pair, D_pair)
    assert sign_nth_pair(R_pair, w_pair) >= 0
    assert cmp_nth_pair(R_pair, D_pair, w_pair) < 0
    return Q, R_pair
Esempio n. 11
0
def _bet_curve_2_(fx, gx, a, b, d_) -> object:
    """Area between Curves 2: Area Bounded by Linear Functions.

    We developed the concept of the definite integral to calculate
    the area below a curve on a given interval. In this section, we
    expand that idea to calculate the area of more complex regions.
    We start by finding the area between two curves that are functions
    of x, beginning with the simple case in which one function value
    is always greater than the other. We then look at cases when the
    graphs of the functions cross. Last, we consider how to calculate
    the area between two curves that are functions of y.

    Let f(x) and g(x) be continuous functions such that f(x) ≥ g(x)
    or f(x) ≤ g(x) over an interval [a,b]. Let R denote the region
    bounded above by the graph of f(x), below by the graph of g(x),
    and on the left and right by the lines x=a and x=b, respectively.
    Therefore, on the interval [a,b], we always have f(x) ≥ g(x) or
    f(x) ≤ g(x). To determine which, we will use a test point located
    between the given interval. Solution:

    - 1: Find where f(x) and g(x) intersect in terms of:
            f(x) = g(x) and solve for x.

    Then, the area of R is given by:

    - A = ∫[a,b] [ f(x) − g(x) ] dx, if f(x) ≥ g(x)
    - A = ∫[a,b] [ g(x) − g(x) ] dx, if f(x) ≤ g(x)

    :param fx: a function of f(x)
    :param gx: a function of g(x)
    :param a: The lower bounds
    :param b: The upper bounds
    :param d_: the variable of integration
    :return:  the area represented by an integral solution
                ∫[a,b] [ f(x) − g(x) ] dx, if f(x) ≥ g(x) or
                ∫[a,b] [ g(x) − f(x) ] dx, if f(x) ≤ g(x)
    """
    if not isinstance(fx, Number) and not isinstance(gx, Number):
        print("\nf(x) & g(x) is not number")
        f_int = Integral(fx, (d_, a, b))
        g_int = Integral(gx, (d_, a, b))
        note = ('\n***Note: The area of the region between the curves is defined as the '
                '\nintegral of the upper curve minus the integral of the lower curve over '
                '\neach region. The regions are determined by the intersection points of '
                '\nthe curves. This can be done algebraically or graphically.\n')
        if a is None and b is None:
            sol_f = solve(fx - gx)
            sol_g = solve(gx - fx)
            print('1. Combine the equations and solve for x.  \n'
                  'f(x) - g(x): x = {0} \n\ng(x) - f(x): x = {1}'.
                  format(pretty(sol_f), pretty(sol_g)))
            if len(solve(sol_f)) <= 1 and fx.subs({d_: sol_f[0]}) >= gx.subs({d_: sol_f[0]}):
                print('Only one solution:')
                a = solve(fx)[0]
                b = sol_f[0]
        else:

            sol_f = solve(fx)
            sol_g = solve(gx)
            print('1. Solve each function for x.  \n'
                  'f(x): x = {0} \n\ng(x): x = {1}'.
                  format(pretty(sol_f), pretty(sol_g)))
        # A = ∫[a,b] [ f(x) − g(x) ] dx, if f(x) ≥ g(x)
        if fx.subs({d_: a}) >= gx.subs({d_: a}):  # if f(x) ≥ g(x)
            print('\nf(x) is above g(x)\n')
            print('\n1. Eliminate the equal sides of each equation and combine '
                  '\nf(x) = g(x): \n\n {0} = {1} \n\n'
                  'If they f(x) ≠ g(x), then move to the next step.'.
                  format(pretty(fx), pretty(gx)))
            print(note)
            print('\nArea = \n\n\n{0}'.
                  format(pretty(f_int - g_int)))
            int_fg = Integral((fx - gx), (d_, a, b))
            print('\n2. Integrate to find the area between {0} and {1}'
                  '\nWe get: \n\n{2}'.format(a, b, pretty(int_fg)))
            print('3. Find the antiderivative, substitute and simplify to get: \n\n'
                  'Area between the curves = {0}'.format(pretty(int_fg.doit())))

        # A = ∫[a,b] [ g(x) − f(x) ] dx, if f(x) ≤ g(x)
        if fx.subs({d_: a}) <= gx.subs({d_: a}):  # if f(x) ≤ g(x)
            print('\ng(x) is above f(x)\n')
            fg = (gx - fx)
            print('1. Eliminate the equal sides of each equation and combine '
                  '\ng(x) = f(x): \n\n {0} = {1} \n\n'
                  'If they f(x) ≠ g(x), then move to the next step.'.
                  format(pretty(gx), pretty(fx)))
            print(note)
            print('\nArea = \n\n\n{0}'.
                  format(pretty(g_int - f_int)))
            int_fg = Integral((gx - fx), (d_, a, b))
            print('\n2. Integrate to find the area between {0} and {1}'
                  '\nWe get: \n\n{2}'.format(a, b, pretty(int_fg)))
            print('3. Find the antiderivative, substitute and simplify to get: \n\n'
                  'Area between the curves = {0}'.format(pretty(int_fg.doit())))

    elif not isinstance(fx, Number) and isinstance(gx, Number):
        print("\nOnly g(x) is a number")
        x = symbols('x')
        expr = Integral((fx - gx), x)
        fg = (fx - gx)
        sol = solve(fg)
        fac = factor(fg)
        _lead_coef_ = LC(fac)
        anti = expr.doit()
        note = ("***Note: If any individual factor on the left side of the \n"
                "equation is equal to 0, the entire expression will be equal to 0.***")
        print('\n\nf(x) = \n\n{0}\n\ng(x) = \n\n{1}\n'.format(fx, gx))
        print('\n\n1. Integrate f(x) & g(x) with respect to {0}: \n\n\n{1} '
              .format(d_, pretty(expr)))
        print('\n2. Comibine and rewrite as:  f(x) = g(x), and set equal to 0: '
              '\n\n\n{0} = 0\n'.format(pretty(fg)))
        print('\n\n3. Simplify and factor: \n\n\n{0}'.format(pretty(fac)))
        # check for and remove any leading coefficients after factoring
        print('\n\n4. Remove any leading coefficient and divide both sides of '
              'the factorials if exists by: "{0}", \nthis will cancel out the leading'
              ' coefficient leaving: \n\n{1}'.format(_lead_coef_, (fac / _lead_coef_)))
        print('\n\n5. Now solve for x:\n{0}\n\nx = {1}'.
              format(note, pretty(sol)))
        print('\n\n6. The final solution is all the values that make {0} = 0 true.'
              '\nIn this case, we substitute all values of x = {1} found in the '
              '\nprevious step to find the coordinates where both functions intersect '
              'each other.'.format(pretty(fac / _lead_coef_), sol))
        print('7. The area of the region between the curves is defined as the '
              '\nintegral of the upper curve minus the integral of the lower curve over '
              '\neach region. The regions are determined by the intersection points of '
              'the curves.')
        print('8. Now we find the antiderivative of our original integration: '
              '\n\n\n{0}\n\n\n\tOur antiderivative with respect to {1} = \n\n\n{2}\n\n'.
              format(pretty(expr), d_, pretty(anti)))
        print('\n\n8.1 Our new Integral using the antiderivative: \n\n\n{}\n\n'.
              format(pretty(Integral(anti, (x, sol[0], sol[1])))))
        print('9. Finally we substitute our intersecting points where the graphs '
              '\nintersect and subract the area under the graph from the area above '
              '\nthe graphs, to find the area between the curves, giving us: \n\n{0}'.
              format(pretty(anti.subs({d_: sol[1]})
                            - anti.subs({d_: sol[0]}))))
    elif isinstance(fx, Number) and isinstance(gx, Number):
        print("\nf(x) & g(x) is a number")
    elif isinstance(fx, Number) and not isinstance(gx, Number):
        print("\nOnly f(x) is a number")