Example #1
0
def _rootof_data(poly, indices):
    """Construct ``RootOf`` data from a polynomial and indices. """
    (_, factors) = poly.factor_list()

    reals = _rootof_get_reals(factors)
    real_count = sum([k for _, _, k in reals])

    if indices is None:
        reals = _rootof_reals_sorted(reals)

        for index in xrange(0, real_count):
            yield _rootof_reals_index(reals, index)
    else:
        if any(index < real_count for index in indices):
            reals = _rootof_reals_sorted(reals)

            for index in indices:
                if index < real_count:
                    yield _rootof_reals_index(reals, index)

        if any(index >= real_count for index in indices):
            complexes = _rootof_get_complexes(factors)
            complexes = _rootof_complexes_sorted(complexes)

            for index in indices:
                if index >= real_count:
                    yield _rootof_complexes_index(complexes,
                                                  index - real_count)
Example #2
0
def _rootof_data(poly, indices):
    """Construct ``RootOf`` data from a polynomial and indices. """
    (_, factors) = poly.factor_list()

    reals = _rootof_get_reals(factors)
    real_count = sum([ k for _, _, k in reals ])

    if indices is None:
        reals = _rootof_reals_sorted(reals)

        for index in xrange(0, real_count):
            yield _rootof_reals_index(reals, index)
    else:
        if any(index < real_count for index in indices):
            reals = _rootof_reals_sorted(reals)

            for index in indices:
                if index < real_count:
                    yield _rootof_reals_index(reals, index)

        if any(index >= real_count for index in indices):
            complexes = _rootof_get_complexes(factors)
            complexes = _rootof_complexes_sorted(complexes)

            for index in indices:
                if index >= real_count:
                    yield _rootof_complexes_index(complexes, index-real_count)
Example #3
0
    def update(G, CP, h):
        """update G using the set of critical pairs CP and h = (expv,pi)
        see [BW] page 230
        """
        hexpv, hp = f[h]
        # print 'DB10',hp
        # filter new pairs (h,g), g in G
        C = G.copy()
        D = set()

        while C:
            # select a pair (h,g) by popping an element from C
            g = C.pop()
            gexpv = f[g][0]
            LCMhg = lcm_expv(hexpv, gexpv)

            def lcm_divides(p):
                expv = lcm_expv(hexpv, f[p][0])
                # LCM(LM(h), LM(p)) divides LCM(LM(h),LM(g))
                return monomial_div(LCMhg, expv)

            # HT(h) and HT(g) disjoint: hexpv + gexpv == LCMhg
            if monomial_mul(hexpv, gexpv) == LCMhg or (
                not any(lcm_divides(f) for f in C) and not any(lcm_divides(pr[1]) for pr in D)
            ):
                D.add((h, g))

        E = set()
        while D:
            # select h,g from D
            h, g = D.pop()
            gexpv = f[g][0]
            LCMhg = lcm_expv(hexpv, gexpv)
            if not monomial_mul(hexpv, gexpv) == LCMhg:
                E.add((h, g))

        # filter old pairs
        B_new = set()

        while CP:
            # select g1,g2 from CP
            g1, g2 = CP.pop()
            g1expv = f[g1][0]
            g2expv = f[g2][0]
            LCM12 = lcm_expv(g1expv, g2expv)
            # if HT(h) does not divide lcm(HT(g1),HT(g2))
            if not monomial_div(LCM12, hexpv) or lcm_expv(g1expv, hexpv) == LCM12 or lcm_expv(g2expv, hexpv) == LCM12:
                B_new.add((g1, g2))

        B_new |= E

        # filter polynomials
        G_new = set()
        while G:
            g = G.pop()
            if not monomial_div(f[g][0], hexpv):
                G_new.add(g)
        G_new.add(h)

        return G_new, B_new
Example #4
0
    def is_univariate(f):
        """Returns True if 'f' is univariate in its last variable. """
        for monom in f.monoms():
            if any(m > 0 for m in monom[:-1]):
                return False

        return True
Example #5
0
def solve_undetermined_coeffs(equ, coeffs, sym, **flags):
    """Solve equation of a type p(x; a_1, ..., a_k) == q(x) where both
       p, q are univariate polynomials and f depends on k parameters.
       The result of this functions is a dictionary with symbolic
       values of those parameters with respect to coefficiens in q.

       This functions accepts both Equations class instances and ordinary
       SymPy expressions. Specification of parameters and variable is
       obligatory for efficiency and simplicity reason.

       >>> from sympy import *
       >>> a, b, c, x = symbols('a', 'b', 'c', 'x')

       >>> solve_undetermined_coeffs(Eq(2*a*x + a+b, x), [a, b], x)
       {a: 1/2, b: -1/2}

       >>> solve_undetermined_coeffs(Eq(a*c*x + a+b, x), [a, b], x)
       {a: 1/c, b: -1/c}

    """
    if isinstance(equ, Equality):
        # got equation, so move all the
        # terms to the left hand side
        equ = equ.lhs - equ.rhs

    system = collect(equ.expand(), sym, evaluate=False).values()

    if not any([equ.has(sym) for equ in system]):
        # consecutive powers in the input expressions have
        # been successfully collected, so solve remaining
        # system using Gaussian ellimination algorithm
        return solve(system, *coeffs, **flags)
    else:
        return None  # no solutions
Example #6
0
def solve_undetermined_coeffs(equ, coeffs, sym, **flags):
    """Solve equation of a type p(x; a_1, ..., a_k) == q(x) where both
       p, q are univariate polynomials and f depends on k parameters.
       The result of this functions is a dictionary with symbolic
       values of those parameters with respect to coefficiens in q.

       This functions accepts both Equations class instances and ordinary
       SymPy expressions. Specification of parameters and variable is
       obligatory for efficiency and simplicity reason.

       >>> from sympy import *
       >>> a, b, c, x = symbols('a', 'b', 'c', 'x')

       >>> solve_undetermined_coeffs(Eq(2*a*x + a+b, x), [a, b], x)
       {a: 1/2, b: -1/2}

       >>> solve_undetermined_coeffs(Eq(a*c*x + a+b, x), [a, b], x)
       {a: 1/c, b: -1/c}

    """
    if isinstance(equ, Equality):
        # got equation, so move all the
        # terms to the left hand side
        equ = equ.lhs - equ.rhs

    system = collect(equ.expand(), sym, evaluate=False).values()

    if not any([ equ.has(sym) for equ in system ]):
        # consecutive powers in the input expressions have
        # been successfully collected, so solve remaining
        # system using Gaussian ellimination algorithm
        return solve(system, *coeffs, **flags)
    else:
        return None # no solutions
Example #7
0
    def is_univariate(f):
        """Returns True if 'f' is univariate in its last variable. """
        for monom in f.monoms():
            if any(m > 0 for m in monom[:-1]):
                return False

        return True
Example #8
0
def gf_Qbasis(Q, p, K):
    """
    Compute a basis of the kernel of ``Q``.

    **Examples**

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_Qmatrix, gf_Qbasis

    >>> gf_Qbasis(gf_Qmatrix([1, 0, 0, 0, 1], 5, ZZ), 5, ZZ)
    [[1, 0, 0, 0], [0, 0, 1, 0]]

    >>> gf_Qbasis(gf_Qmatrix([3, 2, 4], 5, ZZ), 5, ZZ)
    [[1, 0]]

    """
    Q, n = [list(q) for q in Q], len(Q)

    for k in xrange(0, n):
        Q[k][k] = (Q[k][k] - K.one) % p

    for k in xrange(0, n):
        for i in xrange(k, n):
            if Q[k][i]:
                break
        else:
            continue

        inv = K.invert(Q[k][i], p)

        for j in xrange(0, n):
            Q[j][i] = (Q[j][i] * inv) % p

        for j in xrange(0, n):
            t = Q[j][k]
            Q[j][k] = Q[j][i]
            Q[j][i] = t

        for i in xrange(0, n):
            if i != k:
                q = Q[k][i]

                for j in xrange(0, n):
                    Q[j][i] = (Q[j][i] - Q[j][k] * q) % p

    for i in xrange(0, n):
        for j in xrange(0, n):
            if i == j:
                Q[i][j] = (K.one - Q[i][j]) % p
            else:
                Q[i][j] = (-Q[i][j]) % p

    basis = []

    for q in Q:
        if any(q):
            basis.append(q)

    return basis
Example #9
0
def gf_Qbasis(Q, p, K):
    """
    Compute a basis of the kernel of ``Q``.

    **Examples**

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_Qmatrix, gf_Qbasis

    >>> gf_Qbasis(gf_Qmatrix([1, 0, 0, 0, 1], 5, ZZ), 5, ZZ)
    [[1, 0, 0, 0], [0, 0, 1, 0]]

    >>> gf_Qbasis(gf_Qmatrix([3, 2, 4], 5, ZZ), 5, ZZ)
    [[1, 0]]

    """
    Q, n = [ list(q) for q in Q ], len(Q)

    for k in xrange(0, n):
        Q[k][k] = (Q[k][k] - K.one) % p

    for k in xrange(0, n):
        for i in xrange(k, n):
            if Q[k][i]:
                break
        else:
            continue

        inv = K.invert(Q[k][i], p)

        for j in xrange(0, n):
            Q[j][i] = (Q[j][i]*inv) % p

        for j in xrange(0, n):
            t = Q[j][k]
            Q[j][k] = Q[j][i]
            Q[j][i] = t

        for i in xrange(0, n):
            if i != k:
                q = Q[k][i]

                for j in xrange(0, n):
                    Q[j][i] = (Q[j][i] - Q[j][k]*q) % p

    for i in xrange(0, n):
        for j in xrange(0, n):
            if i == j:
                Q[i][j] = (K.one - Q[i][j]) % p
            else:
                Q[i][j] = (-Q[i][j]) % p

    basis = []

    for q in Q:
        if any(q):
            basis.append(q)

    return basis
Example #10
0
def denester(nested):
    """
    Denests a list of expressions that contain nested square roots.
    This method should not be called directly - use 'denest' instead.
    This algorithm is based on <http://www.almaden.ibm.com/cs/people/fagin/symb85.pdf>.

    It is assumed that all of the elements of 'nested' share the same
    bottom-level radicand. (This is stated in the paper, on page 177, in
    the paragraph immediately preceding the algorithm.)

    When evaluating all of the arguments in parallel, the bottom-level
    radicand only needs to be denested once. This means that calling
    denester with x arguments results in a recursive invocation with x+1
    arguments; hence denester has polynomial complexity.

    However, if the arguments were evaluated separately, each call would
    result in two recursive invocations, and the algorithm would have
    exponential complexity.

    This is discussed in the paper in the middle paragraph of page 179.
    """
    if all((n ** 2).is_Number for n in nested):  # If none of the arguments are nested
        for f in subsets(len(nested)):  # Test subset 'f' of nested
            p = prod(nested[i] ** 2 for i in range(len(f)) if f[i]).expand()
            if 1 in f and f.count(1) > 1 and f[-1]:
                p = -p
            if sqrt(p).is_Number:
                return sqrt(p), f  # If we got a perfect square, return its square root.
        return nested[-1], [0] * len(nested)  # Otherwise, return the radicand from the previous invocation.
    else:
        a, b, r, R = Wild("a"), Wild("b"), Wild("r"), None
        values = [expr.match(sqrt(a + b * sqrt(r))) for expr in nested]
        for v in values:
            if r in v:  # Since if b=0, r is not defined
                if R is not None:
                    assert R == v[r]  # All the 'r's should be the same.
                else:
                    R = v[r]
        d, f = denester([sqrt((v[a] ** 2).expand() - (R * v[b] ** 2).expand()) for v in values] + [sqrt(R)])
        if not any([f[i] for i in range(len(nested))]):  # If f[i]=0 for all i < len(nested)
            v = values[-1]
            return sqrt(v[a] + v[b] * d), f
        else:
            v = prod(nested[i] ** 2 for i in range(len(nested)) if f[i]).expand().match(a + b * sqrt(r))
            if 1 in f and f.index(1) < len(nested) - 1 and f[len(nested) - 1]:
                v[a] = -1 * v[a]
                v[b] = -1 * v[b]
            if not f[len(nested)]:  # Solution denests with square roots
                return (
                    (
                        sqrt((v[a] + d).expand() / 2) + sign(v[b]) * sqrt((v[b] ** 2 * R / (2 * (v[a] + d))).expand())
                    ).expand(),
                    f,
                )
            else:  # Solution requires a fourth root
                FR, s = (R.expand() ** Rational(1, 4)), sqrt((v[b] * R).expand() + d)
                return (s / (sqrt(2) * FR) + v[a] * FR / (sqrt(2) * s)).expand(), f
Example #11
0
    def _eval_nseries(self, x, n):
        """
        This function does compute series for multivariate functions,
        but the expansion is always in terms of *one* variable.
        Examples:

        >>> from sympy import atan2, O
        >>> from sympy.abc import x, y
        >>> atan2(x, y).series(x, n=2)
        atan2(0, y) + x/y + O(x**2)
        >>> atan2(x, y).series(y, n=2)
        atan2(x, 0) - y/x + O(y**2)
        """
        if self.func.nargs is None:
            raise NotImplementedError('series for user-defined \
functions are not supported.')
        args = self.args
        args0 = [t.limit(x, 0) for t in args]
        if any([t is S.NaN or t.is_bounded is False for t in args0]):
            raise PoleError("Cannot expand %s around 0" % (args))
        if (self.func.nargs == 1 and args0[0]) or self.func.nargs > 1:
            e = self
            e1 = e.expand()
            if e == e1:
                #for example when e = sin(x+1) or e = sin(cos(x))
                #let's try the general algorithm
                term = e.subs(x, S.Zero)
                if term.is_bounded is False or term is S.NaN:
                    raise PoleError("Cannot expand %s around 0" % (self))
                series = term
                fact = S.One
                for i in range(n-1):
                    i += 1
                    fact *= Rational(i)
                    e = e.diff(x)
                    subs = e.subs(x, S.Zero)
                    if subs is S.NaN:
                        # try to evaluate a limit if we have to
                        subs = e.limit(x, S.Zero)
                    if subs.is_bounded is False:
                        raise PoleError("Cannot expand %s around 0" % (self))
                    term = subs*(x**i)/fact
                    term = term.expand()
                    series += term
                return series + C.Order(x**n, x)
            return e1.nseries(x, n=n)
        arg = self.args[0]
        l = []
        g = None
        for i in xrange(n+2):
            g = self.taylor_term(i, arg, g)
            g = g.nseries(x, n=n)
            l.append(g)
        return Add(*l) + C.Order(x**n, x)
Example #12
0
    def _eval_nseries(self, x, n):
        """
        This function does compute series for multivariate functions,
        but the expansion is always in terms of *one* variable.
        Examples:

        >>> from sympy import atan2, O
        >>> from sympy.abc import x, y
        >>> atan2(x, y).series(x, n=2)
        atan2(0, y) + x/y + O(x**2)
        >>> atan2(x, y).series(y, n=2)
        atan2(x, 0) - y/x + O(y**2)
        """
        if self.func.nargs is None:
            raise NotImplementedError('series for user-defined \
functions are not supported.')
        args = self.args
        args0 = [t.limit(x, 0) for t in args]
        if any([t is S.NaN or t.is_bounded is False for t in args0]):
            raise PoleError("Cannot expand %s around 0" % (args))
        if (self.func.nargs == 1 and args0[0]) or self.func.nargs > 1:
            e = self
            e1 = e.expand()
            if e == e1:
                #for example when e = sin(x+1) or e = sin(cos(x))
                #let's try the general algorithm
                term = e.subs(x, S.Zero)
                if term.is_bounded is False or term is S.NaN:
                    raise PoleError("Cannot expand %s around 0" % (self))
                series = term
                fact = S.One
                for i in range(n - 1):
                    i += 1
                    fact *= Rational(i)
                    e = e.diff(x)
                    subs = e.subs(x, S.Zero)
                    if subs is S.NaN:
                        # try to evaluate a limit if we have to
                        subs = e.limit(x, S.Zero)
                    if subs.is_bounded is False:
                        raise PoleError("Cannot expand %s around 0" % (self))
                    term = subs * (x**i) / fact
                    term = term.expand()
                    series += term
                return series + C.Order(x**n, x)
            return e1.nseries(x, n=n)
        arg = self.args[0]
        l = []
        g = None
        for i in xrange(n + 2):
            g = self.taylor_term(i, arg, g)
            g = g.nseries(x, n=n)
            l.append(g)
        return Add(*l) + C.Order(x**n, x)
Example #13
0
def dmp_zz_wang_lead_coeffs(f, T, cs, E, H, A, u, K):
    """Wang/EEZ: Compute correct leading coefficients. """
    C, J, v = [], [0]*len(E), u-1

    for h in H:
        c = dmp_one(v, K)
        d = dup_LC(h, K)*cs

        for i in reversed(xrange(len(E))):
            k, e, (t, _) = 0, E[i], T[i]

            while not (d % e):
                d, k = d//e, k+1

            if k != 0:
                c, J[i] = dmp_mul(c, dmp_pow(t, k, v, K), v, K), 1

        C.append(c)

    if any([ not j for j in J ]):
        raise ExtraneousFactors # pragma: no cover

    CC, HH = [], []

    for c, h in zip(C, H):
        d = dmp_eval_tail(c, A, v, K)
        lc = dup_LC(h, K)

        if K.is_one(cs):
            cc = lc//d
        else:
            g = K.gcd(lc, d)
            d, cc = d//g, lc//g
            h, cs = dup_mul_ground(h, d, K), cs//d

        c = dmp_mul_ground(c, cc, v, K)

        CC.append(c)
        HH.append(h)

    if K.is_one(cs):
        return f, HH, CC

    CCC, HHH = [], []

    for c, h in zip(CC, HH):
        CCC.append(dmp_mul_ground(c, cs, v, K))
        HHH.append(dmp_mul_ground(h, cs, 0, K))

    f = dmp_mul_ground(f, cs**(len(H)-1), u, K)

    return f, HHH, CCC
Example #14
0
def dmp_zz_wang_lead_coeffs(f, T, cs, E, H, A, u, K):
    """Wang/EEZ: Compute correct leading coefficients. """
    C, J, v = [], [0] * len(E), u - 1

    for h in H:
        c = dmp_one(v, K)
        d = dup_LC(h, K) * cs

        for i in reversed(xrange(len(E))):
            k, e, (t, _) = 0, E[i], T[i]

            while not (d % e):
                d, k = d // e, k + 1

            if k != 0:
                c, J[i] = dmp_mul(c, dmp_pow(t, k, v, K), v, K), 1

        C.append(c)

    if any([not j for j in J]):
        raise ExtraneousFactors  # pragma: no cover

    CC, HH = [], []

    for c, h in zip(C, H):
        d = dmp_eval_tail(c, A, v, K)
        lc = dup_LC(h, K)

        if K.is_one(cs):
            cc = lc // d
        else:
            g = K.gcd(lc, d)
            d, cc = d // g, lc // g
            h, cs = dup_mul_ground(h, d, K), cs // d

        c = dmp_mul_ground(c, cc, v, K)

        CC.append(c)
        HH.append(h)

    if K.is_one(cs):
        return f, HH, CC

    CCC, HHH = [], []

    for c, h in zip(CC, HH):
        CCC.append(dmp_mul_ground(c, cs, v, K))
        HHH.append(dmp_mul_ground(h, cs, 0, K))

    f = dmp_mul_ground(f, cs**(len(H) - 1), u, K)

    return f, HHH, CCC
Example #15
0
    def is_zero(self):
        """Since Integral doesn't autosimplify it it useful to see if
        it would simplify to zero or not in a trivial manner, i.e. when
        the function is 0 or two limits of a definite integral are the same.

        This is a very naive and quick test, not intended to check for special
        patterns like Integral(sin(m*x)*cos(n*x), (x, 0, 2*pi)) == 0.
        """
        if self.function.is_zero or any(len(xab) == 3 and xab[1] == xab[2] for xab in self.limits):
            return True
        if not self.free_symbols and self.function.is_number:
            # the integrand is a number and the limits are numerical
            return False
Example #16
0
def _parallel_dict_from_expr(exprs, opt):
    """Transform expressions into a multinomial form. """
    if opt.expand is not False:
        exprs = [expr.expand() for expr in exprs]

    if any(expr.is_commutative is False for expr in exprs):
        raise PolynomialError('non-commutative expressions are not supported')

    if opt.gens:
        reps, gens = _parallel_dict_from_expr_if_gens(exprs, opt)
    else:
        reps, gens = _parallel_dict_from_expr_no_gens(exprs, opt)

    return reps, opt.clone({'gens': gens})
Example #17
0
    def _find(self, tests, obj, name, module, source_lines, globs, seen):
        """
        Find tests for the given object and any contained objects, and
        add them to `tests`.
        """
        if self._verbose:
            print 'Finding tests in %s' % name

        # If we've already processed this object, then ignore it.
        if id(obj) in seen:
            return
        seen[id(obj)] = 1

        # Make sure we don't run doctests for classes outside of sympy, such
        # as in numpy or scipy.
        if inspect.isclass(obj):
            if obj.__module__.split('.')[0] != 'sympy':
                return

        # Find a test for this object, and add it to the list of tests.
        test = self._get_test(obj, name, module, globs, source_lines)
        if test is not None:
            tests.append(test)

        # Look for tests in a module's contained objects.
        if inspect.ismodule(obj) and self._recurse:
            for rawname, val in obj.__dict__.items():
                # Recurse to functions & classes.
                if inspect.isfunction(val) or inspect.isclass(val):
                    in_module = self._from_module(module, val)
                    if not in_module:
                        # double check in case this function is decorated
                        # and just appears to come from a different module.
                        pat = r'\s*(def|class)\s+%s\s*\(' % rawname
                        PAT = pre.compile(pat)
                        in_module = any(
                            PAT.match(line) for line in source_lines)
                    if in_module:
                        try:
                            valname = '%s.%s' % (name, rawname)
                            self._find(tests, val, valname, module,
                                       source_lines, globs, seen)
                        except ValueError, msg:
                            if "invalid option" in msg.args[0]:
                                # +SKIP raises ValueError in Python 2.4
                                pass
                            else:
                                raise
                        except:
                            pass
Example #18
0
    def preprocess(cls, gens):
        if isinstance(gens, Basic):
            gens = (gens,)
        elif len(gens) == 1 and hasattr(gens[0], '__iter__'):
            gens = gens[0]

        if gens == (None,):
            gens = ()
        elif len(set(gens)) != len(gens):
            raise GeneratorsError("duplicated generators: %s" % str(gens))
        elif any(gen.is_commutative is False for gen in gens):
            raise GeneratorsError("non-commutative generators: %s" % str(gens))

        return tuple(gens)
Example #19
0
    def preprocess(cls, gens):
        if isinstance(gens, Basic):
            gens = (gens,)
        elif len(gens) == 1 and hasattr(gens[0], '__iter__'):
            gens = gens[0]

        if gens == (None,):
            gens = ()
        elif len(set(gens)) != len(gens):
            raise GeneratorsError("duplicated generators: %s" % str(gens))
        elif any(gen.is_commutative is False for gen in gens):
            raise GeneratorsError("non-commutative generators: %s" % str(gens))

        return tuple(gens)
Example #20
0
def _parallel_dict_from_expr(exprs, opt):
    """Transform expressions into a multinomial form. """
    if opt.expand is not False:
        exprs = [ expr.expand() for expr in exprs ]

    if any(expr.is_commutative is False for expr in exprs):
        raise PolynomialError('non-commutative expressions are not supported')

    if opt.gens:
        reps, gens = _parallel_dict_from_expr_if_gens(exprs, opt)
    else:
        reps, gens = _parallel_dict_from_expr_no_gens(exprs, opt)

    return reps, opt.clone({'gens': gens})
Example #21
0
    def is_zero(self):
        """Since Integral doesn't autosimplify it it useful to see if
        it would simplify to zero or not in a trivial manner, i.e. when
        the function is 0 or two limits of a definite integral are the same.

        This is a very naive and quick test, not intended to check for special
        patterns like Integral(sin(m*x)*cos(n*x), (x, 0, 2*pi)) == 0.
        """
        if (self.function.is_zero or
            any(len(xab) == 3 and xab[1] == xab[2] for xab in self.limits)):
            return True
        if not self.free_symbols and self.function.is_number:
            # the integrand is a number and the limits are numerical
            return False
Example #22
0
    def __new__(cls, *args, **options):
        # Handle calls like Function('f')
        if cls is Function:
            return UndefinedFunction(*args)

        args = map(sympify, args)
        evaluate = options.pop('evaluate', True)
        if evaluate:
            evaluated = cls.eval(*args)
            if evaluated is not None:
                return evaluated
        result = super(Application, cls).__new__(cls, *args, **options)
        if evaluate and any([cls._should_evalf(a) for a in args]):
            return result.evalf()
        return result
Example #23
0
    def __new__(cls, *args, **options):
        # Handle calls like Function('f')
        if cls is Function:
            return UndefinedFunction(*args)

        args = map(sympify, args)
        evaluate = options.pop('evaluate', True)
        if evaluate:
            evaluated = cls.eval(*args)
            if evaluated is not None:
                return evaluated
        result = super(Application, cls).__new__(cls, *args, **options)
        if evaluate and any([cls._should_evalf(a) for a in args]):
            return result.evalf()
        return result
Example #24
0
    def _find(self, tests, obj, name, module, source_lines, globs, seen):
        """
        Find tests for the given object and any contained objects, and
        add them to `tests`.
        """
        if self._verbose:
            print 'Finding tests in %s' % name

        # If we've already processed this object, then ignore it.
        if id(obj) in seen:
            return
        seen[id(obj)] = 1

        # Make sure we don't run doctests for classes outside of sympy, such
        # as in numpy or scipy.
        if inspect.isclass(obj):
            if obj.__module__.split('.')[0] != 'sympy':
                return

        # Find a test for this object, and add it to the list of tests.
        test = self._get_test(obj, name, module, globs, source_lines)
        if test is not None:
            tests.append(test)

        # Look for tests in a module's contained objects.
        if inspect.ismodule(obj) and self._recurse:
            for rawname, val in obj.__dict__.items():
                # Recurse to functions & classes.
                if inspect.isfunction(val) or inspect.isclass(val):
                    in_module = self._from_module(module, val)
                    if not in_module:
                        # double check in case this function is decorated
                        # and just appears to come from a different module.
                        pat = r'\s*(def|class)\s+%s\s*\(' % rawname
                        PAT = pre.compile(pat)
                        in_module = any(PAT.match(line) for line in source_lines)
                    if in_module:
                        try:
                            valname = '%s.%s' % (name, rawname)
                            self._find(tests, val, valname, module, source_lines, globs, seen)
                        except ValueError, msg:
                            if "invalid option" in msg.args[0]:
                                # +SKIP raises ValueError in Python 2.4
                                pass
                            else:
                                raise
                        except:
                            pass
Example #25
0
def gf_Qbasis(Q, p, K):
    """Compute a basis of the kernel of `Q`. """
    Q, n = [ list(q) for q in Q ], len(Q)

    for k in xrange(0, n):
        Q[k][k] = (Q[k][k] - K.one) % p

    for k in xrange(0, n):
        for i in xrange(k, n):
            if Q[k][i]:
                break
        else:
            continue

        inv = K.invert(Q[k][i], p)

        for j in xrange(0, n):
            Q[j][i] = (Q[j][i]*inv) % p

        for j in xrange(0, n):
            t = Q[j][k]
            Q[j][k] = Q[j][i]
            Q[j][i] = t

        for i in xrange(0, n):
            if i != k:
                q = Q[k][i]

                for j in xrange(0, n):
                    Q[j][i] = (Q[j][i] - Q[j][k]*q) % p

    for i in xrange(0, n):
        for j in xrange(0, n):
            if i == j:
                Q[i][j] = (K.one - Q[i][j]) % p
            else:
                Q[i][j] = (-Q[i][j]) % p

    basis = []

    for q in Q:
        if any(q):
            basis.append(q)

    return basis
Example #26
0
def dup_zz_cyclotomic_factor(f, K):
    """Efficiently factor polynomials `x**n - 1` and `x**n + 1` in `Z[x]`.

       Given a univariate polynomial `f` in `Z[x]` returns a list of factors
       of `f`, provided that `f` is in the form `x**n - 1` or `x**n + 1` for
       `n >= 1`. Otherwise returns None.

       Factorization is performed using using cyclotomic decomposition of `f`,
       which makes this method much faster that any other direct factorization
       approach (e.g. Zassenhaus's).

       References
       ==========

       .. [Weisstein09] Eric W. Weisstein, Cyclotomic Polynomial, From MathWorld - A
           Wolfram Web Resource, http://mathworld.wolfram.com/CyclotomicPolynomial.html

    """
    lc_f, tc_f = dup_LC(f, K), dup_TC(f, K)

    if dup_degree(f) <= 0:
        return None

    if lc_f != 1 or tc_f not in [-1, 1]:
        return None

    if any([bool(cf) for cf in f[1:-1]]):
        return None

    n = dup_degree(f)
    F = _dup_cyclotomic_decompose(n, K)

    if not K.is_one(tc_f):
        return F
    else:
        H = []

        for h in _dup_cyclotomic_decompose(2 * n, K):
            if h not in F:
                H.append(h)

        return H
Example #27
0
def dup_zz_cyclotomic_factor(f, K):
    """Efficiently factor polynomials `x**n - 1` and `x**n + 1` in `Z[x]`.

       Given a univariate polynomial `f` in `Z[x]` returns a list of factors
       of `f`, provided that `f` is in the form `x**n - 1` or `x**n + 1` for
       `n >= 1`. Otherwise returns None.

       Factorization is performed using using cyclotomic decomposition of `f`,
       which makes this method much faster that any other direct factorization
       approach (e.g. Zassenhaus's).

       References
       ==========

       .. [Weisstein09] Eric W. Weisstein, Cyclotomic Polynomial, From MathWorld - A
           Wolfram Web Resource, http://mathworld.wolfram.com/CyclotomicPolynomial.html

    """
    lc_f, tc_f = dup_LC(f, K), dup_TC(f, K)

    if dup_degree(f) <= 0:
        return None

    if lc_f != 1 or tc_f not in [-1, 1]:
        return None

    if any([ bool(cf) for cf in f[1:-1] ]):
        return None

    n = dup_degree(f)
    F = _dup_cyclotomic_decompose(n, K)

    if not K.is_one(tc_f):
        return F
    else:
        H = []

        for h in _dup_cyclotomic_decompose(2*n, K):
            if h not in F:
                H.append(h)

        return H
Example #28
0
def test(*args, **kwargs):
    """
    Run all tests containing any of the given strings in their path.

    If sort=False, run them in random order (not default).

    Warning: Tests in *very* deeply nested directories are not found.

    Examples:

    >> import sympy

    Run all tests:
    >> sympy.test()

    Run one file:
    >> sympy.test("sympy/core/tests/test_basic.py")

    Run all tests in sympy/functions/ and some particular file:
    >> sympy.test("sympy/core/tests/test_basic.py", "sympy/functions")

    Run all tests in sympy/core and sympy/utilities:
    >> sympy.test("core", "util")
    """
    from glob import glob
    verbose = kwargs.get("verbose", False)
    tb = kwargs.get("tb", "short")
    kw = kwargs.get("kw", "")
    post_mortem = kwargs.get("pdb", False)
    colors = kwargs.get("colors", True)
    sort = kwargs.get("sort", True)
    r = PyTestReporter(verbose, tb, colors)
    t = SymPyTests(r, kw, post_mortem)
    if len(args) == 0:
        t.add_paths(["sympy"])
    else:
        mypaths = []
        for p in t.get_paths(dir='sympy'):
            mypaths.extend(glob(p))
        mypaths = set(mypaths)
        t.add_paths([p for p in mypaths if any(a in p for a in args)])
    return t.test(sort=sort)
Example #29
0
 def __new__(cls, *args, **options):
     args = map(sympify, args)
     # these lines should be refactored
     for opt in ["nargs", "dummy", "comparable", "noncommutative", "commutative"]:
         if opt in options:
             del options[opt]
     # up to here.
     if not options.pop('evaluate', True):
         return super(Application, cls).__new__(cls, *args, **options)
     evaluated = cls.eval(*args)
     if evaluated is not None:
         return evaluated
     # Just undefined functions have nargs == None
     if not cls.nargs and hasattr(cls, 'undefined_Function'):
         r = super(Application, cls).__new__(cls, *args, **options)
         r.nargs = len(args)
         return r
     r = super(Application, cls).__new__(cls, *args, **options)
     if any([cls._should_evalf(a) for a in args]):
         return r.evalf()
     return r
Example #30
0
 def __new__(cls, *args, **options):
     args = map(sympify, args)
     # these lines should be refactored
     for opt in [
             "nargs", "dummy", "comparable", "noncommutative", "commutative"
     ]:
         if opt in options:
             del options[opt]
     # up to here.
     if not options.pop('evaluate', True):
         return super(Application, cls).__new__(cls, *args, **options)
     evaluated = cls.eval(*args)
     if evaluated is not None:
         return evaluated
     # Just undefined functions have nargs == None
     if not cls.nargs and hasattr(cls, 'undefined_Function'):
         r = super(Application, cls).__new__(cls, *args, **options)
         r.nargs = len(args)
         return r
     r = super(Application, cls).__new__(cls, *args, **options)
     if any([cls._should_evalf(a) for a in args]):
         return r.evalf()
     return r
Example #31
0
def _construct_composite(coeffs, opt):
    """Handle composite domains, e.g.: ZZ[X], QQ[X], ZZ(X), QQ(X). """
    numers, denoms = [], []

    for coeff in coeffs:
        numer, denom = coeff.as_numer_denom()

        numers.append(numer)
        denoms.append(denom)

    polys, gens = parallel_dict_from_basic(numers + denoms) # XXX: sorting

    if any(gen.is_number for gen in gens):
        return None # generators are number-like so lets better use EX

    n = len(gens)
    k = len(polys)//2

    numers = polys[:k]
    denoms = polys[k:]

    if opt.field:
        fractions = True
    else:
        fractions, zeros = False, (0,)*n

        for denom in denoms:
            if len(denom) > 1 or zeros not in denom:
                fractions = True
                break

    result = []

    if not fractions:
        coeffs = set([])

        for numer, denom in zip(numers, denoms):
            denom = denom[zeros]

            for monom, coeff in numer.iteritems():
                coeff /= denom
                coeffs.add(coeff)
                numer[monom] = coeff

        rationals, reals = False, False

        for coeff in coeffs:
            if coeff.is_Rational:
                if not coeff.is_Integer:
                    rationals = True
            elif coeff.is_Real:
                reals = True
                break

        if reals:
            ground = RR
        elif rationals:
            ground = QQ
        else:
            ground = ZZ

        domain = ground.poly_ring(*gens)

        for numer in numers:
            for monom, coeff in numer.iteritems():
                numer[monom] = ground.from_sympy(coeff)

            result.append(domain(numer))
    else:
        domain = ZZ.frac_field(*gens)

        for numer, denom in zip(numers, denoms):
            for monom, coeff in numer.iteritems():
                numer[monom] = ZZ.from_sympy(coeff)

            for monom, coeff in denom.iteritems():
                denom[monom] = ZZ.from_sympy(coeff)

            result.append(domain((numer, denom)))

    return domain, result
Example #32
0
def doctest(*paths, **kwargs):
    """
    Runs doctests in all *py files in the sympy directory which match
    any of the given strings in `paths` or all tests if paths=[].

    Note:
       o paths can be entered in native system format or in unix,
         forward-slash format.
       o files that are on the blacklist can be tested by providing
         their path; they are only excluded if no paths are given.

    Examples:

    >> froms sympy.utilities.runtests import doctest

    Run all tests:
    >> doctest()

    Run one file:
    >> doctest("sympy/core/basic.py")
    >> doctest("polynomial.txt")

    Run all tests in sympy/functions/ and some particular file:
    >> doctest("/functions", "basic.py")

    Run any file having polynomial in its name, doc/src/modules/polynomial.txt,
    sympy\functions\special\polynomials.py, and sympy\polys\polynomial.py:
    >> doctest("polynomial")
    """
    normal = kwargs.get("normal", False)
    verbose = kwargs.get("verbose", False)
    blacklist = kwargs.get("blacklist", [])
    blacklist.extend([
        "sympy/thirdparty/pyglet",  # segfaults
        "doc/src/modules/mpmath",  # needs to be fixed upstream
        "sympy/mpmath",  # needs to be fixed upstream
        "doc/src/modules/plotting.txt",  # generates live plots
        "sympy/plotting",  # generates live plots
        "sympy/utilities/compilef.py",  # needs tcc
        "sympy/utilities/autowrap.py",  # needs installed compiler
        "sympy/galgebra/GA.py",  # needs numpy
        "sympy/galgebra/latex_ex.py",  # needs numpy
        "sympy/conftest.py",  # needs py.test
        "sympy/utilities/benchmarking.py",  # needs py.test
    ])
    blacklist = convert_to_native_paths(blacklist)

    r = PyTestReporter(verbose)
    t = SymPyDocTests(r, normal)

    test_files = t.get_test_files('sympy')
    not_blacklisted = [
        f for f in test_files if not any(b in f for b in blacklist)
    ]
    if len(paths) == 0:
        t._testfiles.extend(not_blacklisted)
    else:
        # take only what was requested...but not blacklisted items
        # and allow for partial match anywhere or fnmatch of name
        paths = convert_to_native_paths(paths)
        matched = []
        for f in not_blacklisted:
            basename = os.path.basename(f)
            for p in paths:
                if p in f or fnmatch(basename, p):
                    matched.append(f)
                    break
        t._testfiles.extend(matched)

    # run the tests and record the result for this *py portion of the tests
    if t._testfiles:
        failed = not t.test()
    else:
        failed = False

    # test *txt files only if we are running python newer than 2.4
    if sys.version_info[:2] > (2, 4):

        # N.B.
        # --------------------------------------------------------------------
        # Here we test *.txt files at or below doc/src. Code from these must
        # be self supporting in terms of imports since there is no importing
        # of necessary modules by doctest.testfile. If you try to pass *.py
        # files through this they might fail because they will lack the needed
        # imports and smarter parsing that can be done with source code.
        #
        test_files = t.get_test_files('doc/src', '*.txt', init_only=False)
        test_files.sort()

        not_blacklisted = [
            f for f in test_files if not any(b in f for b in blacklist)
        ]

        if len(paths) == 0:
            matched = not_blacklisted
        else:
            # Take only what was requested as long as it's not on the blacklist.
            # Paths were already made native in *py tests so don't repeat here.
            # There's no chance of having a *py file slip through since we
            # only have *txt files in test_files.
            matched = []
            for f in not_blacklisted:
                basename = os.path.basename(f)
                for p in paths:
                    if p in f or fnmatch(basename, p):
                        matched.append(f)
                        break

        setup_pprint()
        first_report = True
        for txt_file in matched:
            if not os.path.isfile(txt_file):
                continue
            old_displayhook = sys.displayhook
            try:
                # out = pdoctest.testfile(txt_file, module_relative=False, encoding='utf-8',
                #    optionflags=pdoctest.ELLIPSIS | pdoctest.NORMALIZE_WHITESPACE)
                out = sympytestfile(txt_file,
                                    module_relative=False,
                                    encoding='utf-8',
                                    optionflags=pdoctest.ELLIPSIS
                                    | pdoctest.NORMALIZE_WHITESPACE)
            finally:
                # make sure we return to the original displayhook in case some
                # doctest has changed that
                sys.displayhook = old_displayhook

            txtfailed, tested = out
            if tested:
                failed = txtfailed or failed
                if first_report:
                    first_report = False
                    msg = 'txt doctests start'
                    lhead = '=' * ((80 - len(msg)) // 2 - 1)
                    rhead = '=' * (79 - len(msg) - len(lhead) - 1)
                    print ' '.join([lhead, msg, rhead])
                    print
                # use as the id, everything past the first 'sympy'
                file_id = txt_file[txt_file.find('sympy') + len('sympy') + 1:]
                print file_id,  # get at least the name out so it is know who is being tested
                wid = 80 - len(file_id) - 1  #update width
                test_file = '[%s]' % (tested)
                report = '[%s]' % (txtfailed or 'OK')
                print ''.join([
                    test_file, ' ' * (wid - len(test_file) - len(report)),
                    report
                ])

        # the doctests for *py will have printed this message already if there was
        # a failure, so now only print it if there was intervening reporting by
        # testing the *txt as evidenced by first_report no longer being True.
        if not first_report and failed:
            print
            print("DO *NOT* COMMIT!")
    return not failed
Example #33
0
def tsolve(eq, sym):
    """
    Solves a transcendental equation with respect to the given
    symbol. Various equations containing mixed linear terms, powers,
    and logarithms, can be solved.

    Only a single solution is returned. This solution is generally
    not unique. In some cases, a complex solution may be returned
    even though a real solution exists.

        >>> from sympy import tsolve, log
        >>> from sympy.abc import x

        >>> tsolve(3**(2*x+5)-4, x)
        [(-5*log(3) + log(4))/(2*log(3))]

        >>> tsolve(log(x) + 2*x, x)
        [LambertW(2)/2]

    """
    if patterns is None:
        _generate_patterns()
    eq = sympify(eq)
    if isinstance(eq, Equality):
        eq = eq.lhs - eq.rhs
    sym = sympify(sym)
    eq2 = eq.subs(sym, x)
    # First see if the equation has a linear factor
    # In that case, the other factor can contain x in any way (as long as it
    # is finite), and we have a direct solution to which we add others that
    # may be found for the remaining portion.
    r = Wild("r")
    m = eq2.match((a * x + b) * r)
    if m and m[a]:
        return [(-b / a).subs(m).subs(x, sym)] + solve(m[r], x)
    for p, sol in patterns:
        m = eq2.match(p)
        if m:
            return [sol.subs(m).subs(x, sym)]

    # let's also try to inverse the equation
    lhs = eq
    rhs = S.Zero

    while True:
        indep, dep = lhs.as_independent(sym)

        # dep + indep == rhs
        if lhs.is_Add:
            # this indicates we have done it all
            if indep is S.Zero:
                break

            lhs = dep
            rhs -= indep

        # dep * indep == rhs
        else:
            # this indicates we have done it all
            if indep is S.One:
                break

            lhs = dep
            rhs /= indep

    #                    -1
    # f(x) = g  ->  x = f  (g)
    if lhs.is_Function and lhs.nargs == 1 and hasattr(lhs, "inverse"):
        rhs = lhs.inverse()(rhs)
        lhs = lhs.args[0]

        sol = solve(lhs - rhs, sym)
        return sol

    elif lhs.is_Add:
        # just a simple case - we do variable substitution for first function,
        # and if it removes all functions - let's call solve.
        #      x    -x                   -1
        # UC: e  + e   = y      ->  t + t   = y
        t = Dummy("t")
        terms = lhs.args

        # find first term which is Function
        for f1 in lhs.args:
            if f1.is_Function:
                break
        else:
            raise NotImplementedError(
                "Unable to solve the equation" + "(tsolve: at least one Function expected at this point"
            )

        # perform the substitution
        lhs_ = lhs.subs(f1, t)

        # if no Functions left, we can proceed with usual solve
        if not (lhs_.is_Function or any(term.is_Function for term in lhs_.args)):
            cv_sols = solve(lhs_ - rhs, t)
            for sol in cv_sols:
                if sol.has(sym):
                    raise NotImplementedError("Unable to solve the equation")
            cv_inv = solve(t - f1, sym)[0]
            sols = list()
            for sol in cv_sols:
                sols.append(cv_inv.subs(t, sol))
            return sols

    raise NotImplementedError("Unable to solve the equation.")
Example #34
0
def solve(f, *symbols, **flags):
    """Solves equations and systems of equations.

       Currently supported are univariate polynomial, transcendental
       equations, piecewise combinations thereof and systems of linear
       and polynomial equations.  Input is formed as a single expression
       or an equation,  or an iterable container in case of an equation
       system.  The type of output may vary and depends heavily on the
       input. For more details refer to more problem specific functions.

       By default all solutions are simplified to make the output more
       readable. If this is not the expected behavior (e.g., because of
       speed issues) set simplified=False in function arguments.

       To solve equations and systems of equations like recurrence relations
       or differential equations, use rsolve() or dsolve(), respectively.

       >>> from sympy import I, solve
       >>> from sympy.abc import x, y

       Solve a polynomial equation:

       >>> solve(x**4-1, x)
       [1, -1, -I, I]

       Solve a linear system:

       >>> solve((x+5*y-2, -3*x+6*y-15), x, y)
       {x: -3, y: 1}

    """

    def sympit(w):
        return map(sympify, iff(isinstance(w, (list, tuple, set)), w, [w]))

    # make f and symbols into lists of sympified quantities
    # keeping track of how f was passed since if it is a list
    # a dictionary of results will be returned.
    bare_f = not isinstance(f, (list, tuple, set))
    f, symbols = (sympit(w) for w in [f, symbols])

    if any(isinstance(fi, bool) or (fi.is_Relational and not fi.is_Equality) for fi in f):
        return reduce_inequalities(f, assume=flags.get("assume"))

    for i, fi in enumerate(f):
        if fi.is_Equality:
            f[i] = fi.lhs - fi.rhs

    if not symbols:
        # get symbols from equations or supply dummy symbols since
        # solve(3,x) returns []...though it seems that it should raise some sort of error TODO
        symbols = set([])
        for fi in f:
            symbols |= fi.atoms(Symbol) or set([Dummy("x")])
        symbols = list(symbols)

    if bare_f:
        f = f[0]
    if len(symbols) == 1:
        if isinstance(symbols[0], (list, tuple, set)):
            symbols = symbols[0]

    result = list()

    # Begin code handling for Function and Derivative instances
    # Basic idea:  store all the passed symbols in symbols_passed, check to see
    # if any of them are Function or Derivative types, if so, use a dummy
    # symbol in their place, and set symbol_swapped = True so that other parts
    # of the code can be aware of the swap.  Once all swapping is done, the
    # continue on with regular solving as usual, and swap back at the end of
    # the routine, so that whatever was passed in symbols is what is returned.
    symbols_new = []
    symbol_swapped = False

    symbols_passed = list(symbols)

    for i, s in enumerate(symbols):
        if s.is_Symbol:
            s_new = s
        elif s.is_Function:
            symbol_swapped = True
            s_new = Dummy("F%d" % i)
        elif s.is_Derivative:
            symbol_swapped = True
            s_new = Dummy("D%d" % i)
        else:
            raise TypeError("not a Symbol or a Function")
        symbols_new.append(s_new)

        if symbol_swapped:
            swap_back_dict = dict(zip(symbols_new, symbols))
    # End code for handling of Function and Derivative instances

    if not isinstance(f, (tuple, list, set)):

        # Create a swap dictionary for storing the passed symbols to be solved
        # for, so that they may be swapped back.
        if symbol_swapped:
            swap_dict = zip(symbols, symbols_new)
            f = f.subs(swap_dict)
            symbols = symbols_new

        # Any embedded piecewise functions need to be brought out to the
        # top level so that the appropriate strategy gets selected.
        f = piecewise_fold(f)

        if len(symbols) != 1:
            result = {}
            for s in symbols:
                result[s] = solve(f, s, **flags)
            if flags.get("simplified", True):
                for s, r in result.items():
                    result[s] = map(simplify, r)
            return result

        symbol = symbols[0]
        strategy = guess_solve_strategy(f, symbol)

        if strategy == GS_POLY:
            poly = f.as_poly(symbol)
            if poly is None:
                raise NotImplementedError("Cannot solve equation " + str(f) + " for " + str(symbol))
            # for cubics and quartics, if the flag wasn't set, DON'T do it
            # by default since the results are quite long. Perhaps one could
            # base this decision on a certain crtical length of the roots.
            if poly.degree > 2:
                flags["simplified"] = flags.get("simplified", False)
            result = roots(poly, cubics=True, quartics=True).keys()

        elif strategy == GS_RATIONAL:
            P, Q = f.as_numer_denom()
            # TODO: check for Q != 0
            result = solve(P, symbol, **flags)

        elif strategy == GS_POLY_CV_1:
            args = list(f.args)
            if isinstance(f, Add):
                # we must search for a suitable change of variable
                # collect exponents
                exponents_denom = list()
                for arg in args:
                    if isinstance(arg, Pow):
                        exponents_denom.append(arg.exp.q)
                    elif isinstance(arg, Mul):
                        for mul_arg in arg.args:
                            if isinstance(mul_arg, Pow):
                                exponents_denom.append(mul_arg.exp.q)
                assert len(exponents_denom) > 0
                if len(exponents_denom) == 1:
                    m = exponents_denom[0]
                else:
                    # get the LCM of the denominators
                    m = reduce(ilcm, exponents_denom)
                # x -> y**m.
                # we assume positive for simplification purposes
                t = Dummy("t", positive=True)
                f_ = f.subs(symbol, t ** m)
                if guess_solve_strategy(f_, t) != GS_POLY:
                    raise NotImplementedError("Could not convert to a polynomial equation: %s" % f_)
                cv_sols = solve(f_, t)
                for sol in cv_sols:
                    result.append(sol ** m)

            elif isinstance(f, Mul):
                for mul_arg in args:
                    result.extend(solve(mul_arg, symbol))

        elif strategy == GS_POLY_CV_2:
            m = 0
            args = list(f.args)
            if isinstance(f, Add):
                for arg in args:
                    if isinstance(arg, Pow):
                        m = min(m, arg.exp)
                    elif isinstance(arg, Mul):
                        for mul_arg in arg.args:
                            if isinstance(mul_arg, Pow):
                                m = min(m, mul_arg.exp)
            elif isinstance(f, Mul):
                for mul_arg in args:
                    if isinstance(mul_arg, Pow):
                        m = min(m, mul_arg.exp)
            f1 = simplify(f * symbol ** (-m))
            result = solve(f1, symbol)
            # TODO: we might have introduced unwanted solutions
            # when multiplied by x**-m

        elif strategy == GS_PIECEWISE:
            result = set()
            for expr, cond in f.args:
                candidates = solve(expr, *symbols)
                if isinstance(cond, bool) or cond.is_Number:
                    if not cond:
                        continue

                    # Only include solutions that do not match the condition
                    # of any of the other pieces.
                    for candidate in candidates:
                        matches_other_piece = False
                        for other_expr, other_cond in f.args:
                            if isinstance(other_cond, bool) or other_cond.is_Number:
                                continue
                            if bool(other_cond.subs(symbol, candidate)):
                                matches_other_piece = True
                                break
                        if not matches_other_piece:
                            result.add(candidate)
                else:
                    for candidate in candidates:
                        if bool(cond.subs(symbol, candidate)):
                            result.add(candidate)

            result = list(result)

        elif strategy == GS_TRANSCENDENTAL:
            # a, b = f.as_numer_denom()
            # Let's throw away the denominator for now. When we have robust
            # assumptions, it should be checked, that for the solution,
            # b!=0.
            result = tsolve(f, *symbols)
        elif strategy == -1:
            raise ValueError("Could not parse expression %s" % f)
        else:
            raise NotImplementedError("No algorithms are implemented to solve equation %s" % f)

        # This symbol swap should not be necessary for the single symbol case: if you've
        # solved for the symbol the it will not appear in the solution. Right now, however
        # ode's are getting solutions for solve (even though they shouldn't be -- see the
        # swap_back test in test_solvers).
        if symbol_swapped:
            result = [ri.subs(swap_back_dict) for ri in result]

        if flags.get("simplified", True) and strategy != GS_RATIONAL:
            return map(simplify, result)
        else:
            return result
    else:
        if not f:
            return {}
        else:
            # Create a swap dictionary for storing the passed symbols to be
            # solved for, so that they may be swapped back.
            if symbol_swapped:
                swap_dict = zip(symbols, symbols_new)
                f = [fi.subs(swap_dict) for fi in f]
                symbols = symbols_new

            polys = []

            for g in f:

                poly = g.as_poly(*symbols)

                if poly is not None:
                    polys.append(poly)
                else:
                    raise NotImplementedError()

            if all(p.is_linear for p in polys):
                n, m = len(f), len(symbols)
                matrix = zeros((n, m + 1))

                for i, poly in enumerate(polys):
                    for monom, coeff in poly.terms():
                        try:
                            j = list(monom).index(1)
                            matrix[i, j] = coeff
                        except ValueError:
                            matrix[i, m] = -coeff

                soln = solve_linear_system(matrix, *symbols, **flags)
            else:
                soln = solve_poly_system(polys)

            # Use swap_dict to ensure we return the same type as what was
            # passed
            if symbol_swapped:
                if isinstance(soln, dict):
                    res = {}
                    for k in soln.keys():
                        res.update({swap_back_dict[k]: soln[k]})
                    return res
                else:
                    return soln
            else:
                return soln
Example #35
0
def solve(f, *symbols, **flags):
    """Solves equations and systems of equations.

       Currently supported are univariate polynomial and transcendental
       equations and systems of linear and polynomial equations.  Input
       is formed as a single expression or an equation,  or an iterable
       container in case of an equation system.  The type of output may
       vary and depends heavily on the input. For more details refer to
       more problem specific functions.

       By default all solutions are simplified to make the output more
       readable. If this is not the expected behavior,  eg. because of
       speed issues, set simplified=False in function arguments.

       To solve equations and systems of equations of other kind, eg.
       recurrence relations of differential equations use rsolve() or
       dsolve() functions respectively.

       >>> from sympy import *
       >>> x,y = symbols('xy')

       Solve a polynomial equation:

       >>> solve(x**4-1, x)
       [1, -1, -I, I]

       Solve a linear system:

       >>> solve((x+5*y-2, -3*x+6*y-15), x, y)
       {x: -3, y: 1}

    """
    if not symbols:
        raise ValueError('no symbols were given')

    if len(symbols) == 1:
        if isinstance(symbols[0], (list, tuple, set)):
            symbols = symbols[0]

    symbols = map(sympify, symbols)

    if any(not s.is_Symbol for s in symbols):
        raise TypeError('not a Symbol')

    if not isinstance(f, (tuple, list, set)):
        f = sympify(f)

        if isinstance(f, Equality):
            f = f.lhs - f.rhs

        if len(symbols) != 1:
            raise NotImplementedError('multivariate equation')

        symbol = symbols[0]

        strategy = guess_solve_strategy(f, symbol)

        if strategy == GS_POLY:
            poly = f.as_poly( symbol )
            assert poly is not None
            result = roots(poly, cubics=True, quartics=True).keys()

        elif strategy == GS_RATIONAL:
            P, Q = f.as_numer_denom()
            #TODO: check for Q != 0
            return solve(P, symbol, **flags)

        elif strategy == GS_POLY_CV_1:
            args = list(f.args)
            if isinstance(f, Add):
                # we must search for a suitable change of variable
                # collect exponents
                exponents_denom = list()
                for arg in args:
                    if isinstance(arg, Pow):
                        exponents_denom.append(arg.exp.q)
                    elif isinstance(arg, Mul):
                        for mul_arg in arg.args:
                            if isinstance(mul_arg, Pow):
                                exponents_denom.append(mul_arg.exp.q)
                assert len(exponents_denom) > 0
                if len(exponents_denom) == 1:
                    m = exponents_denom[0]
                else:
                    # get the GCD of the denominators
                    m = ilcm(*exponents_denom)
                # x -> y**m.
                # we assume positive for simplification purposes
                t = Symbol('t', positive=True, dummy=True)
                f_ = f.subs(symbol, t**m)
                if guess_solve_strategy(f_, t) != GS_POLY:
                    raise TypeError("Could not convert to a polynomial equation: %s" % f_)
                cv_sols = solve(f_, t)
                result = list()
                for sol in cv_sols:
                    result.append(sol**m)

            elif isinstance(f, Mul):
                result = []
                for mul_arg in args:
                    result.extend(solve(mul_arg, symbol))

        elif strategy == GS_POLY_CV_2:
            m = 0
            args = list(f.args)
            if isinstance(f, Add):
                for arg in args:
                    if isinstance(arg, Pow):
                        m = min(m, arg.exp)
                    elif isinstance(arg, Mul):
                        for mul_arg in arg.args:
                            if isinstance(mul_arg, Pow):
                                m = min(m, mul_arg.exp)
            elif isinstance(f, Mul):
                for mul_arg in args:
                    if isinstance(mul_arg, Pow):
                        m = min(m, mul_arg.exp)
            f1 = simplify(f*symbol**(-m))
            result = solve(f1, symbol)
            # TODO: we might have introduced unwanted solutions
            # when multiplied by x**-m

        elif strategy == GS_TRASCENDENTAL:
            #a, b = f.as_numer_denom()
            # Let's throw away the denominator for now. When we have robust
            # assumptions, it should be checked, that for the solution,
            # b!=0.
            result = tsolve(f, *symbols)
        elif strategy == -1:
            raise Exception('Could not parse expression %s' % f)
        else:
            raise NotImplementedError("No algorithms where implemented to solve equation %s" % f)

        if flags.get('simplified', True):
            return map(simplify, result)
        else:
            return result
    else:
        if not f:
            return {}
        else:
            polys = []

            for g in f:
                g = sympify(g)

                if isinstance(g, Equality):
                    g = g.lhs - g.rhs

                poly = g.as_poly(*symbols)

                if poly is not None:
                    polys.append(poly)
                else:
                    raise NotImplementedError()

            if all(p.is_linear for p in polys):
                n, m = len(f), len(symbols)
                matrix = zeros((n, m + 1))

                for i, poly in enumerate(polys):
                    for coeff, monom in poly.iter_terms():
                        try:
                            j = list(monom).index(1)
                            matrix[i, j] = coeff
                        except ValueError:
                            matrix[i, m] = -coeff

                return solve_linear_system(matrix, *symbols, **flags)
            else:
                return solve_poly_system(polys)
Example #36
0
def doctest(*paths, **kwargs):
    """
    Runs doctests in all *py files in the sympy directory which match
    any of the given strings in `paths` or all tests if paths=[].

    Note:
       o paths can be entered in native system format or in unix,
         forward-slash format.
       o files that are on the blacklist can be tested by providing
         their path; they are only excluded if no paths are given.

    Examples:

    >> import sympy

    Run all tests:
    >> sympy.doctest()

    Run one file:
    >> sympy.doctest("sympy/core/basic.py")
    >> sympy.doctest("polynomial.txt")

    Run all tests in sympy/functions/ and some particular file:
    >> sympy.doctest("/functions", "basic.py")

    Run any file having polynomial in its name, doc/src/modules/polynomial.txt,
    sympy\functions\special\polynomials.py, and sympy\polys\polynomial.py:
    >> sympy.doctest("polynomial")
    """
    normal = kwargs.get("normal", False)
    verbose = kwargs.get("verbose", False)
    blacklist = kwargs.get("blacklist", [])
    blacklist.extend([
                    "sympy/thirdparty/pyglet", # segfaults
                    "doc/src/modules/mpmath", # needs to be fixed upstream
                    "sympy/mpmath", # needs to be fixed upstream
                    "doc/src/modules/plotting.txt", # generates live plots
                    "sympy/plotting", # generates live plots
                    "sympy/utilities/compilef.py", # needs tcc
                    "sympy/utilities/autowrap.py", # needs installed compiler
                    "sympy/galgebra/GA.py", # needs numpy
                    "sympy/galgebra/latex_ex.py", # needs numpy
                    "sympy/conftest.py", # needs py.test
                    "sympy/utilities/benchmarking.py", # needs py.test
                    ])
    blacklist = convert_to_native_paths(blacklist)

    # Disable warnings for external modules
    import sympy.external
    sympy.external.importtools.WARN_OLD_VERSION = False
    sympy.external.importtools.WARN_NOT_INSTALLED = False

    r = PyTestReporter(verbose)
    t = SymPyDocTests(r, normal)

    test_files = t.get_test_files('sympy')
    not_blacklisted = [f for f in test_files
                         if not any(b in f for b in blacklist)]
    if len(paths) == 0:
        t._testfiles.extend(not_blacklisted)
    else:
        # take only what was requested...but not blacklisted items
        # and allow for partial match anywhere or fnmatch of name
        paths = convert_to_native_paths(paths)
        matched = []
        for f in not_blacklisted:
            basename = os.path.basename(f)
            for p in paths:
                if p in f or fnmatch(basename, p):
                    matched.append(f)
                    break
        t._testfiles.extend(matched)

    # run the tests and record the result for this *py portion of the tests
    if t._testfiles:
        failed = not t.test()
    else:
        failed = False

    # test *txt files only if we are running python newer than 2.4
    if sys.version_info[:2] > (2,4):

        # N.B.
        # --------------------------------------------------------------------
        # Here we test *.txt files at or below doc/src. Code from these must
        # be self supporting in terms of imports since there is no importing
        # of necessary modules by doctest.testfile. If you try to pass *.py
        # files through this they might fail because they will lack the needed
        # imports and smarter parsing that can be done with source code.
        #
        test_files = t.get_test_files('doc/src', '*.txt', init_only=False)
        test_files.sort()

        not_blacklisted = [f for f in test_files
                             if not any(b in f for b in blacklist)]

        if len(paths) == 0:
            matched = not_blacklisted
        else:
            # Take only what was requested as long as it's not on the blacklist.
            # Paths were already made native in *py tests so don't repeat here.
            # There's no chance of having a *py file slip through since we
            # only have *txt files in test_files.
            matched =  []
            for f in not_blacklisted:
                basename = os.path.basename(f)
                for p in paths:
                    if p in f or fnmatch(basename, p):
                        matched.append(f)
                        break

        setup_pprint()
        first_report = True
        for txt_file in matched:
            if not os.path.isfile(txt_file):
                continue
            old_displayhook = sys.displayhook
            try:
                # out = pdoctest.testfile(txt_file, module_relative=False, encoding='utf-8',
                #    optionflags=pdoctest.ELLIPSIS | pdoctest.NORMALIZE_WHITESPACE)
                out = sympytestfile(txt_file, module_relative=False, encoding='utf-8',
                    optionflags=pdoctest.ELLIPSIS | pdoctest.NORMALIZE_WHITESPACE)
            finally:
                # make sure we return to the original displayhook in case some
                # doctest has changed that
                sys.displayhook = old_displayhook

            txtfailed, tested = out
            if tested:
                failed = txtfailed or failed
                if first_report:
                    first_report = False
                    msg = 'txt doctests start'
                    lhead = '='*((80 - len(msg))//2 - 1)
                    rhead = '='*(79 - len(msg) - len(lhead) - 1)
                    print ' '.join([lhead, msg, rhead])
                    print
                # use as the id, everything past the first 'sympy'
                file_id = txt_file[txt_file.find('sympy') + len('sympy') + 1:]
                print file_id, # get at least the name out so it is know who is being tested
                wid = 80 - len(file_id) - 1 #update width
                test_file = '[%s]' % (tested)
                report = '[%s]' % (txtfailed or 'OK')
                print ''.join([test_file,' '*(wid-len(test_file)-len(report)), report])

        # the doctests for *py will have printed this message already if there was
        # a failure, so now only print it if there was intervening reporting by
        # testing the *txt as evidenced by first_report no longer being True.
        if not first_report and failed:
            print
            print("DO *NOT* COMMIT!")
    return not failed
Example #37
0
    def update(G, B, ih):
        # update G using the set of critical pairs B and h
        # [BW] page 230
        h = f[ih]
        mh = sdp_LM(h, u)

        # filter new pairs (h, g), g in G
        C = G.copy()
        D = set()

        while C:
            # select a pair (h, g) by popping an element from C
            ig = C.pop()
            g = f[ig]
            mg = sdp_LM(g, u)
            LCMhg = monomial_lcm(mh, mg)

            def lcm_divides(ip):
                # LCM(LM(h), LM(p)) divides LCM(LM(h), LM(g))
                m = monomial_lcm(mh, sdp_LM(f[ip], u))
                return monomial_div(LCMhg, m)

            # HT(h) and HT(g) disjoint: mh*mg == LCMhg
            if monomial_mul(mh, mg) == LCMhg or (
                not any(lcm_divides(ipx) for ipx in C) and not any(lcm_divides(pr[1]) for pr in D)
            ):
                D.add((ih, ig))

        E = set()

        while D:
            # select h, g from D (h the same as above)
            ih, ig = D.pop()
            mg = sdp_LM(f[ig], u)
            LCMhg = monomial_lcm(mh, mg)

            if not monomial_mul(mh, mg) == LCMhg:
                E.add((ih, ig))

        # filter old pairs
        B_new = set()

        while B:
            # select g1, g2 from B (-> CP)
            ig1, ig2 = B.pop()
            mg1 = sdp_LM(f[ig1], u)
            mg2 = sdp_LM(f[ig2], u)
            LCM12 = monomial_lcm(mg1, mg2)

            # if HT(h) does not divide lcm(HT(g1), HT(g2))
            if not monomial_div(LCM12, mh) or monomial_lcm(mg1, mh) == LCM12 or monomial_lcm(mg2, mh) == LCM12:
                B_new.add((ig1, ig2))

        B_new |= E

        # filter polynomials
        G_new = set()

        while G:
            ig = G.pop()
            mg = sdp_LM(f[ig], u)

            if not monomial_div(mg, mh):
                G_new.add(ig)

        G_new.add(ih)

        return G_new, B_new
Example #38
0
    def _eval_nseries(self, x, n, logx):
        """
        This function does compute series for multivariate functions,
        but the expansion is always in terms of *one* variable.
        Examples:

        >>> from sympy import atan2, O
        >>> from sympy.abc import x, y
        >>> atan2(x, y).series(x, n=2)
        atan2(0, y) + x/y + O(x**2)
        >>> atan2(x, y).series(y, n=2)
        atan2(x, 0) - y/x + O(y**2)

        This function also computes asymptotic expansions, if necessary
        and possible:

        >>> from sympy import loggamma
        >>> loggamma(1/x)._eval_nseries(x,0,None)
        log(x)/2 - log(x)/x - 1/x + O(1)
        """
        if self.func.nargs is None:
            raise NotImplementedError('series for user-defined \
functions are not supported.')
        args = self.args
        args0 = [t.limit(x, 0) for t in args]
        if any([t.is_bounded == False for t in args0]):
            from sympy import Dummy, oo, zoo, nan
            a = [t.compute_leading_term(x, logx=logx) for t in args]
            a0 = [t.limit(x, 0) for t in a]
            if any([t.has(oo, -oo, zoo, nan) for t in a0]):
                return self._eval_aseries(n, args0, x,
                                          logx)._eval_nseries(x, n, logx)
            # Careful: the argument goes to oo, but only logarithmically so. We
            # are supposed to do a power series expansion "around the
            # logarithmic term". e.g.
            #      f(1+x+log(x))
            #     -> f(1+logx) + x*f'(1+logx) + O(x**2)
            # where 'logx' is given in the argument
            a = [t._eval_nseries(x, n, logx) for t in args]
            z = [r - r0 for (r, r0) in zip(a, a0)]
            p = [Dummy() for t in z]
            q = []
            v = None
            w = None
            for ai, zi, pi in zip(a0, z, p):
                if zi.has(x):
                    if v is not None: raise NotImplementedError
                    q.append(ai + pi)
                    v = pi
                    w = zi
                else:
                    q.append(ai)
            e1 = self.func(*q)
            if v is None:
                return e1
            s = e1._eval_nseries(v, n, logx)
            o = s.getO()
            s = s.removeO()
            s = s.subs(v, zi).expand() + C.Order(o.expr.subs(v, zi), x)
            return s
        if (self.func.nargs == 1 and args0[0]) or self.func.nargs > 1:
            e = self
            e1 = e.expand()
            if e == e1:
                #for example when e = sin(x+1) or e = sin(cos(x))
                #let's try the general algorithm
                term = e.subs(x, S.Zero)
                if term.is_bounded is False or term is S.NaN:
                    raise PoleError("Cannot expand %s around 0" % (self))
                series = term
                fact = S.One
                for i in range(n - 1):
                    i += 1
                    fact *= Rational(i)
                    e = e.diff(x)
                    subs = e.subs(x, S.Zero)
                    if subs is S.NaN:
                        # try to evaluate a limit if we have to
                        subs = e.limit(x, S.Zero)
                    if subs.is_bounded is False:
                        raise PoleError("Cannot expand %s around 0" % (self))
                    term = subs * (x**i) / fact
                    term = term.expand()
                    series += term
                return series + C.Order(x**n, x)
            return e1.nseries(x, n=n, logx=logx)
        arg = self.args[0]
        l = []
        g = None
        for i in xrange(n + 2):
            g = self.taylor_term(i, arg, g)
            g = g.nseries(x, n=n, logx=logx)
            l.append(g)
        return Add(*l) + C.Order(x**n, x)
Example #39
0
def solve(f, *symbols, **flags):
    """
    Algebraically solves equations and systems of equations.

        Currently supported are:
            - univariate polynomial,
            - transcendental
            - piecewise combinations of the above
            - systems of linear and polynomial equations
            - sytems containing relational expressions.

        Input is formed as:
            f
                - a single Expr or Poly that must be zero,
                - an Equality
                - a Relational expression or boolean
                - iterable of one or more of the above

            symbols (Symbol, Function or Derivative) specified as
                - none given (all free symbols will be used)
                - single symbol
                - denested list of symbols
                  e.g. solve(f, x, y)
                - ordered iterable of symbols
                  e.g. solve(f, [x, y])

            flags
                - ``simplified``, when False, will not simplify solutions
                                 (default=True except for polynomials of
                                  order 3 or greater)

        The output varies according to the input and can be seen by example:

            >>> from sympy import solve, Poly, Eq, Function, exp
            >>> from sympy.abc import x, y, z, a, b

            o boolean or univariate Relational

                >>> solve(x < 3)
                And(im(x) == 0, re(x) < 3)

            o single expression and single symbol that is in the expression

                >>> solve(x - y, x)
                [y]
                >>> solve(x - 3, x)
                [3]
                >>> solve(Eq(x, 3), x)
                [3]
                >>> solve(Poly(x - 3), x)
                [3]
                >>> solve(x**2 - y**2, x)
                [y, -y]
                >>> solve(x**4 - 1, x)
                [1, -1, -I, I]

            o single expression with no symbol that is in the expression

                >>> solve(3, x)
                []
                >>> solve(x - 3, y)
                []

            o when no symbol is given then all free symbols will be used
              and sorted with default_sort_key and the result will be the
              same as above as if those symbols had been supplied

                >>> solve(x - 3)
                [3]
                >>> solve(x**2 - y**2)
                [y, -y]

            o when a Function or Derivative is given as a symbol, it is isolated
              algebraically and an implicit solution may be obtained

                >>> f = Function('f')
                >>> solve(f(x) - x, f(x))
                [x]
                >>> solve(f(x).diff(x) - f(x) - x, f(x).diff(x))
                [x + f(x)]

            o single expression and more than 1 symbol

                when there is a linear solution
                    >>> solve(x - y**2, x, y)
                    {x: y**2}
                    >>> solve(x**2 - y, x, y)
                    {y: x**2}

                when undetermined coefficients are identified
                    that are linear
                        >>> solve((a + b)*x - b + 2, a, b)
                        {a: -2, b: 2}

                    that are nonlinear
                        >>> solve((a + b)*x - b**2 + 2, a, b)
                        [(-2**(1/2), 2**(1/2)), (2**(1/2), -2**(1/2))]

                if there is no linear solution then the first successful
                attempt for a nonlinear solution will be returned
                    >>> solve(x**2 - y**2, x, y)
                    [y, -y]
                    >>> solve(x**2 - y**2/exp(x), x, y)
                    [x*exp(x/2), -x*exp(x/2)]

            o iterable of one or more of the above

                involving relationals or bools
                    >>> solve([x < 3, x - 2])
                    And(im(x) == 0, re(x) == 2)
                    >>> solve([x > 3, x - 2])
                    False

                when the system is linear
                    with a solution
                        >>> solve([x - 3], x)
                        {x: 3}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y)
                        {x: -3, y: 1}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y, z)
                        {x: -3, y: 1}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - z), z, x, y)
                        {x: -5*y + 2, z: 21*y - 6}

                    without a solution
                        >>> solve([x + 3, x - 3])

                when the system is not linear
                    >>> solve([x**2 + y -2, y**2 - 4], x, y)
                    [(-2, -2), (0, 2), (0, 2), (2, -2)]

                Warning: there is a possibility of obtaining ambiguous results
                if no symbols are given for a nonlinear system of equations or
                are given as a set since the symbols are not presently reported
                with the solution. A warning will be issued in this situation.
                    >>> solve([x - 2, x**2 + y])
                    <BLANKLINE>
                        For nonlinear systems of equations, symbols should be
                        given as a list so as to avoid ambiguity in the results.
                        solve sorted the symbols as [x, y]
                    [(2, -4)]

                    >>> solve([x - 2, x**2 + f(x)], set([f(x), x]))
                    <BLANKLINE>
                        For nonlinear systems of equations, symbols should be
                        given as a list so as to avoid ambiguity in the results.
                        solve sorted the symbols as [x, f(x)]
                    [(2, -4)]

       See also:
          rsolve() for solving recurrence relationships
          dsolve() for solving differential equations

    """
    # make f and symbols into lists of sympified quantities
    # keeping track of how f was passed since if it is a list
    # a dictionary of results will be returned.
    ###########################################################################
    def sympified_list(w):
        return map(sympify, iff(iterable(w), w, [w]))
    bare_f = not iterable(f)
    ordered_symbols = (symbols and
                       symbols[0] and
                       (isinstance(symbols[0], Symbol) or
                        ordered_iter(symbols[0], include=GeneratorType)
                       )
                      )
    f, symbols = (sympified_list(w) for w in [f, symbols])

    # preprocess equation(s)
    ###########################################################################
    for i, fi in enumerate(f):
        if isinstance(fi, Equality):
            f[i] = fi.lhs - fi.rhs
        elif isinstance(fi, Poly):
            f[i] = fi.as_expr()
        elif isinstance(fi, bool) or fi.is_Relational:
            return reduce_inequalities(f, assume=flags.get('assume'))
        # Any embedded piecewise functions need to be brought out to the
        # top level so that the appropriate strategy gets selected.
        f[i] = piecewise_fold(f[i])

    # preprocess symbol(s)
    ###########################################################################
    if not symbols:
        # get symbols from equations or supply dummy symbols so solve(3) behaves
        # like solve(3, x).
        symbols = set([])
        for fi in f:
            symbols |= fi.free_symbols or set([Dummy()])
        ordered_symbols = False
    elif len(symbols) == 1 and iterable(symbols[0]):
        symbols = symbols[0]
    if not ordered_symbols:
        # we do this to make the results returned canonical in case f
        # contains a system of nonlinear equations; all other cases should
        # be unambiguous
        symbols = sorted(symbols, key=lambda i: i.sort_key())

    # we can solve for Function and Derivative instances by replacing them
    # with Dummy symbols
    symbols_new = []
    symbol_swapped = False
    symbols_passed = list(symbols)

    for i, s in enumerate(symbols):
        if s.is_Symbol:
            s_new = s
        elif s.is_Function:
            symbol_swapped = True
            s_new = Dummy('F%d' % i)
        elif s.is_Derivative:
            symbol_swapped = True
            s_new = Dummy('D%d' % i)
        else:
            msg = 'expected Symbol, Function or Derivative but got %s'
            raise TypeError(msg % type(s))
        symbols_new.append(s_new)

    if symbol_swapped:
        swap_back_dict = dict(zip(symbols_new, symbols))
        swap_dict = zip(symbols, symbols_new)
        f = [fi.subs(swap_dict) for fi in f]
        symbols = symbols_new

    #
    # try to get a solution
    ###########################################################################
    if bare_f:
        # pass f the way it was passed to solve; if it wasn't a list then
        # a list of solutions will be returned, otherwise a dictionary is
        # going to be returned
        f = f[0]
    solution = _solve(f, *symbols, **flags)

    #
    # postprocessing
    ###########################################################################
    # Restore original Functions and Derivatives if a dictionary is returned.
    # This is not necessary for
    #   - the single equation, single unknown case
    #     since the symbol will have been removed from the solution;
    #   - the nonlinear poly_system since that only support zero-dimensional
    #     systems and those results come back as a list
    if symbol_swapped and type(solution) is dict:
            solution = dict([(swap_back_dict[k], v.subs(swap_back_dict))
                              for k, v in solution.iteritems()])
    # warn if ambiguous results are being obtained
    # XXX agree on how to make this unambiguous
    # see issue 2405 for logic in how Polys chooses ordering and
    # for discussion of what to return see http://groups.google.com/group/sympy
    #                           Apr 18, 2011 posting 'using results from solve'
    elif (not ordered_symbols and len(symbols) > 1 and solution and
          ordered_iter(solution) and ordered_iter(solution[0]) and
          any(len(set(s)) > 1 for s in solution)):
        msg = ('\n\tFor nonlinear systems of equations, symbols should be' +
               '\n\tgiven as a list so as to avoid ambiguity in the results.' +
               '\n\tsolve sorted the symbols as %s')
        print msg % str(bool(symbol_swapped) and list(zip(*swap_dict)[0]) or symbols)
    #
    # done
    ###########################################################################
    return solution
Example #40
0
def powsimp(expr, deep=False, combine='all'):
    """
    == Usage ==
        Reduces expression by combining powers with similar bases and exponents.

    == Notes ==
        If deep is True then powsimp() will also simplify arguments of
        functions. By default deep is set to False.
        You can make powsimp() only combine bases or only combine exponents by
        changing combine='base' or combine='exp'.  By default, combine='all',
        which does both.  combine='base' will only combine::

             a   a          a                          2x      x
            x * y  =>  (x*y)   as well as things like 2   =>  4

        and combine='exp' will only combine
        ::

             a   b      (a + b)
            x * x  =>  x

        combine='exp' will strictly only combine exponents in the way that used
        to be automatic.  Also use deep=True if you need the old behavior.

    == Examples ==
        >>> from sympy import *
        >>> x,n = map(Symbol, 'xn')
        >>> e = x**n * (x*n)**(-n) * n
        >>> powsimp(e)
        n**(1 - n)

        >>> powsimp(log(e))
        log(n*x**n*(n*x)**(-n))

        >>> powsimp(log(e), deep=True)
        log(n**(1 - n))

        >>> powsimp(e, combine='exp')
        n*x**n*(n*x)**(-n)
        >>> powsimp(e, combine='base')
        n*(1/n)**n

        >>> y, z = symbols('yz')
        >>> a = x**y*x**z*n**z*n**y
        >>> powsimp(a, combine='exp')
        n**(y + z)*x**(y + z)
        >>> powsimp(a, combine='base')
        (n*x)**y*(n*x)**z
        >>> powsimp(a, combine='all')
        (n*x)**(y + z)
    """
    if combine not in ['all', 'exp', 'base']:
        raise ValueError, "combine must be one of ('all', 'exp', 'base')."
    if combine in ('all', 'base'):
        expr = separate(expr, deep)
    y = Symbol('y', dummy=True)
    if expr.is_Pow:
        if deep:
            return powsimp(y*powsimp(expr.base, deep, combine)**powsimp(\
            expr.exp, deep, combine), deep, combine)/y
        else:
            return powsimp(y * expr, deep,
                           combine) / y  # Trick it into being a Mul
    elif expr.is_Function:
        if expr.func == exp and deep:
            # Exp should really be like Pow
            return powsimp(y * exp(powsimp(expr.args[0], deep, combine)), deep,
                           combine) / y
        elif expr.func == exp and not deep:
            return powsimp(y * expr, deep, combine) / y
        elif deep:
            return expr.func(*[powsimp(t, deep, combine) for t in expr.args])
        else:
            return expr
    elif expr.is_Add:
        return C.Add(*[powsimp(t, deep, combine) for t in expr.args])

    elif expr.is_Mul:
        if combine in ('exp', 'all'):
            # Collect base/exp data, while maintaining order in the
            # non-commutative parts of the product
            if combine is 'all' and deep and any(
                (t.is_Add for t in expr.args)):
                # Once we get to 'base', there is no more 'exp', so we need to
                # distribute here.
                return powsimp(expand_mul(expr, deep=False), deep, combine)
            c_powers = {}
            nc_part = []
            newexpr = sympify(1)
            for term in expr.args:
                if term.is_Add and deep:
                    newexpr *= powsimp(term, deep, combine)
                else:
                    if term.is_commutative:
                        b, e = term.as_base_exp()
                        c_powers[b] = c_powers.get(b, 0) + e
                    else:
                        nc_part.append(term)
            newexpr = Mul(newexpr,
                          Mul(*(Pow(b, e) for b, e in c_powers.items())))
            if combine is 'exp':
                return Mul(newexpr, Mul(*nc_part))
            else:
                # combine is 'all', get stuff ready for 'base'
                if deep:
                    newexpr = expand_mul(newexpr, deep=False)
                if newexpr.is_Add:
                    return powsimp(Mul(*nc_part), deep, combine='base') * Add(
                        *(powsimp(i, deep, combine='base')
                          for i in newexpr.args))
                else:
                    return powsimp(Mul(*nc_part), deep, combine='base')*\
                    powsimp(newexpr, deep, combine='base')

        else:
            # combine is 'base'
            if deep:
                expr = expand_mul(expr, deep=False)
            if expr.is_Add:
                return Add(*(powsimp(i, deep, combine) for i in expr.args))
            else:
                # Build c_powers and nc_part.  These must both be lists not
                # dicts because exp's are not combined.
                c_powers = []
                nc_part = []
                for term in expr.args:
                    if term.is_commutative:
                        c_powers.append(list(term.as_base_exp()))
                    else:
                        nc_part.append(term)

            # Pull out numerical coefficients from exponent
            # e.g., 2**(2*x) => 4**x
            for i in xrange(len(c_powers)):
                b, e = c_powers[i]
                exp_c, exp_t = e.as_coeff_terms()
                if not (exp_c is S.One) and exp_t:
                    c_powers[i] = [C.Pow(b, exp_c), C.Mul(*exp_t)]

            # Combine bases whenever they have the same exponent which is
            # not numeric
            c_exp = {}
            for b, e in c_powers:
                if e in c_exp:
                    c_exp[e].append(b)
                else:
                    c_exp[e] = [b]
            # Merge back in the results of the above to form a new product
            for e in c_exp:
                bases = c_exp[e]
                if deep:
                    simpe = powsimp(e, deep, combine)
                    c_exp = {}
                    for b, ex in c_powers:
                        if ex in c_exp:
                            c_exp[ex].append(b)
                        else:
                            c_exp[ex] = [b]
                    del c_exp[e]
                    c_exp[simpe] = bases

                else:
                    simpe = e
                if len(bases) > 1:
                    for b in bases:
                        c_powers.remove([b, e])
                    new_base = Mul(*bases)
                    in_c_powers = False
                    for i in xrange(len(c_powers)):
                        if c_powers[i][0] == new_base:
                            if combine == 'all':
                                c_powers[i][1] += simpe
                            else:
                                c_powers.append([new_base, simpe])
                            in_c_powers = True
                    if not in_c_powers:
                        c_powers.append([new_base, simpe])
            c_part = [C.Pow(b, e) for b, e in c_powers]
            return C.Mul(*(c_part + nc_part))
    else:
        return expr
Example #41
0
    def update(G, CP, h):
        """update G using the set of critical pairs CP and h = (expv,pi)
        see [BW] page 230
        """
        hexpv, hp = f[h]
        #print 'DB10',hp
        # filter new pairs (h,g), g in G
        C = G.copy()
        D = set()

        while C:
            # select a pair (h,g) by popping an element from C
            g = C.pop()
            gexpv = f[g][0]
            LCMhg = lcm_expv(hexpv, gexpv)

            def lcm_divides(p):
                expv = lcm_expv(hexpv, f[p][0])
                # LCM(LM(h), LM(p)) divides LCM(LM(h),LM(g))
                return monomial_div(LCMhg, expv)

            # HT(h) and HT(g) disjoint: hexpv + gexpv == LCMhg
            if monomial_mul(hexpv,gexpv) == LCMhg or (\
              not any( lcm_divides(f) for f in C ) and \
              not any( lcm_divides(pr[1]) for pr in D )):
                D.add((h, g))

        E = set()
        while D:
            # select h,g from D
            h, g = D.pop()
            gexpv = f[g][0]
            LCMhg = lcm_expv(hexpv, gexpv)
            if not monomial_mul(hexpv, gexpv) == LCMhg:
                E.add((h, g))

        # filter old pairs
        B_new = set()

        while CP:
            # select g1,g2 from CP
            g1, g2 = CP.pop()
            g1expv = f[g1][0]
            g2expv = f[g2][0]
            LCM12 = lcm_expv(g1expv, g2expv)
            # if HT(h) does not divide lcm(HT(g1),HT(g2))
            if not monomial_div(LCM12, hexpv) or \
              lcm_expv(g1expv,hexpv) == LCM12 or \
              lcm_expv(g2expv,hexpv) == LCM12:
                B_new.add((g1, g2))

        B_new |= E

        # filter polynomials
        G_new = set()
        while G:
            g = G.pop()
            if not monomial_div(f[g][0], hexpv):
                G_new.add(g)
        G_new.add(h)

        return G_new, B_new
Example #42
0
def solve_linear_system(system, *symbols, **flags):
    """Solve system of N linear equations with M variables, which means
       both Cramer and over defined systems are supported. The possible
       number of solutions is zero, one or infinite. Respectively this
       procedure will return None or dictionary with solutions. In the
       case of over defined system all arbitrary parameters are skipped.
       This may cause situation in with empty dictionary is returned.
       In this case it means all symbols can be assigned arbitrary values.

       Input to this functions is a Nx(M+1) matrix, which means it has
       to be in augmented form. If you are unhappy with such setting
       use 'solve' method instead, where you can input equations
       explicitly. And don't worry about the matrix, this function
       is persistent and will make a local copy of it.

       The algorithm used here is fraction free Gaussian elimination,
       which results, after elimination, in upper-triangular matrix.
       Then solutions are found using back-substitution. This approach
       is more efficient and compact than the Gauss-Jordan method.

       >>> from sympy import Matrix, solve_linear_system
       >>> from sympy.abc import x, y

       Solve the following system:

              x + 4 y ==  2
           -2 x +   y == 14

       >>> system = Matrix(( (1, 4, 2), (-2, 1, 14)))
       >>> solve_linear_system(system, x, y)
       {x: -6, y: 2}

    """
    matrix = system[:, :]
    syms = list(symbols)

    i, m = 0, matrix.cols - 1  # don't count augmentation

    while i < matrix.rows:
        if i == m:
            # an overdetermined system
            if any(matrix[i:, m]):
                return None  # no solutions
            else:
                # remove trailing rows
                matrix = matrix[:i, :]
                break

        if not matrix[i, i]:
            # there is no pivot in current column
            # so try to find one in other columns
            for k in xrange(i + 1, m):
                if matrix[i, k]:
                    break
            else:
                if matrix[i, m]:
                    return None  # no solutions
                else:
                    # zero row or was a linear combination of
                    # other rows so now we can safely skip it
                    matrix.row_del(i)
                    continue

            # we want to change the order of colums so
            # the order of variables must also change
            syms[i], syms[k] = syms[k], syms[i]
            matrix.col_swap(i, k)

        pivot_inv = S.One / matrix[i, i]

        # divide all elements in the current row by the pivot
        matrix.row(i, lambda x, _: x * pivot_inv)

        for k in xrange(i + 1, matrix.rows):
            if matrix[k, i]:
                coeff = matrix[k, i]

                # subtract from the current row the row containing
                # pivot and multiplied by extracted coefficient
                matrix.row(k, lambda x, j: simplify(x - matrix[i, j] * coeff))

        i += 1

    # if there weren't any problems, augmented matrix is now
    # in row-echelon form so we can check how many solutions
    # there are and extract them using back substitution

    simplified = flags.get('simplified', True)

    if len(syms) == matrix.rows:
        # this system is Cramer equivalent so there is
        # exactly one solution to this system of equations
        k, solutions = i - 1, {}

        while k >= 0:
            content = matrix[k, m]

            # run back-substitution for variables
            for j in xrange(k + 1, m):
                content -= matrix[k, j] * solutions[syms[j]]

            if simplified:
                solutions[syms[k]] = simplify(content)
            else:
                solutions[syms[k]] = content

            k -= 1

        return solutions
    elif len(syms) > matrix.rows:
        # this system will have infinite number of solutions
        # dependent on exactly len(syms) - i parameters
        k, solutions = i - 1, {}

        while k >= 0:
            content = matrix[k, m]

            # run back-substitution for variables
            for j in xrange(k + 1, i):
                content -= matrix[k, j] * solutions[syms[j]]

            # run back-substitution for parameters
            for j in xrange(i, m):
                content -= matrix[k, j] * syms[j]

            if simplified:
                solutions[syms[k]] = simplify(content)
            else:
                solutions[syms[k]] = content

            k -= 1

        return solutions
    else:
        return None  # no solutions
Example #43
0
def tsolve(eq, sym):
    """
    Solves a transcendental equation with respect to the given
    symbol. Various equations containing mixed linear terms, powers,
    and logarithms, can be solved.

    Only a single solution is returned. This solution is generally
    not unique. In some cases, a complex solution may be returned
    even though a real solution exists.

        >>> from sympy import tsolve, log
        >>> from sympy.abc import x

        >>> tsolve(3**(2*x+5)-4, x)
        [(-5*log(3) + log(4))/(2*log(3))]

        >>> tsolve(log(x) + 2*x, x)
        [LambertW(2)/2]

    """
    if patterns is None:
        _generate_patterns()
    eq = sympify(eq)
    if isinstance(eq, Equality):
        eq = eq.lhs - eq.rhs
    sym = sympify(sym)
    eq2 = eq.subs(sym, x)
    # First see if the equation has a linear factor
    # In that case, the other factor can contain x in any way (as long as it
    # is finite), and we have a direct solution to which we add others that
    # may be found for the remaining portion.
    r = Wild('r')
    m = eq2.match((a * x + b) * r)
    if m and m[a]:
        return [(-b / a).subs(m).subs(x, sym)] + solve(m[r], x)
    for p, sol in patterns:
        m = eq2.match(p)
        if m:
            return [sol.subs(m).subs(x, sym)]

    # let's also try to inverse the equation
    lhs = eq
    rhs = S.Zero

    while True:
        indep, dep = lhs.as_independent(sym)

        # dep + indep == rhs
        if lhs.is_Add:
            # this indicates we have done it all
            if indep is S.Zero:
                break

            lhs = dep
            rhs -= indep

        # dep * indep == rhs
        else:
            # this indicates we have done it all
            if indep is S.One:
                break

            lhs = dep
            rhs /= indep

    #                    -1
    # f(x) = g  ->  x = f  (g)
    if lhs.is_Function and lhs.nargs == 1 and hasattr(lhs, 'inverse'):
        rhs = lhs.inverse()(rhs)
        lhs = lhs.args[0]

        sol = solve(lhs - rhs, sym)
        return sol

    elif lhs.is_Add:
        # just a simple case - we do variable substitution for first function,
        # and if it removes all functions - let's call solve.
        #      x    -x                   -1
        # UC: e  + e   = y      ->  t + t   = y
        t = Dummy('t')
        terms = lhs.args

        # find first term which is Function
        for f1 in lhs.args:
            if f1.is_Function:
                break
        else:
            raise NotImplementedError("Unable to solve the equation" + \
                "(tsolve: at least one Function expected at this point")

        # perform the substitution
        lhs_ = lhs.subs(f1, t)

        # if no Functions left, we can proceed with usual solve
        if not (lhs_.is_Function or any(term.is_Function
                                        for term in lhs_.args)):
            cv_sols = solve(lhs_ - rhs, t)
            for sol in cv_sols:
                if sol.has(sym):
                    raise NotImplementedError("Unable to solve the equation")
            cv_inv = solve(t - f1, sym)[0]
            sols = list()
            for sol in cv_sols:
                sols.append(cv_inv.subs(t, sol))
            return sols

    raise NotImplementedError("Unable to solve the equation.")
Example #44
0
    def _find(self, tests, obj, name, module, source_lines, globs, seen):
        """
        Find tests for the given object and any contained objects, and
        add them to `tests`.
        """
        if self._verbose:
            print 'Finding tests in %s' % name

        # If we've already processed this object, then ignore it.
        if id(obj) in seen:
            return
        seen[id(obj)] = 1

        # Find a test for this object, and add it to the list of tests.
        test = self._get_test(obj, name, module, globs, source_lines)
        if test is not None:
            tests.append(test)

        # Look for tests in a module's contained objects.
        if inspect.ismodule(obj) and self._recurse:
            for rawname, val in obj.__dict__.items():
                # Recurse to functions & classes.
                if inspect.isfunction(val) or inspect.isclass(val):
                    in_module = self._from_module(module, val)
                    if not in_module:
                        # double check in case this function is decorated
                        # and just appears to come from a different module.
                        pat = r'\s*(def|class)\s+%s\s*\(' % rawname
                        PAT = pre.compile(pat)
                        in_module = any(PAT.match(line) for line in source_lines)
                    if in_module:
                        try:
                            valname = '%s.%s' % (name, rawname)
                            self._find(tests, val, valname, module, source_lines, globs, seen)
                        except:
                            pass

        # Look for tests in a module's __test__ dictionary.
        if inspect.ismodule(obj) and self._recurse:
            for valname, val in getattr(obj, '__test__', {}).items():
                if not isinstance(valname, basestring):
                    raise ValueError("SymPyDocTestFinder.find: __test__ keys "
                                     "must be strings: %r" %
                                     (type(valname),))
                if not (inspect.isfunction(val) or inspect.isclass(val) or
                        inspect.ismethod(val) or inspect.ismodule(val) or
                        isinstance(val, basestring)):
                    raise ValueError("SymPyDocTestFinder.find: __test__ values "
                                     "must be strings, functions, methods, "
                                     "classes, or modules: %r" %
                                     (type(val),))
                valname = '%s.__test__.%s' % (name, valname)
                self._find(tests, val, valname, module, source_lines,
                           globs, seen)

        # Look for tests in a class's contained objects.
        if inspect.isclass(obj) and self._recurse:
            for valname, val in obj.__dict__.items():
                # Special handling for staticmethod/classmethod.
                if isinstance(val, staticmethod):
                    val = getattr(obj, valname)
                if isinstance(val, classmethod):
                    val = getattr(obj, valname).im_func

                # Recurse to methods, properties, and nested classes.
                if (inspect.isfunction(val) or
                     inspect.isclass(val) or
                     isinstance(val, property)):
                    in_module = self._from_module(module, val)
                    if not in_module:
                        # "double check" again
                        pat = r'\s*(def|class)\s+%s\s*\(' % valname
                        PAT = pre.compile(pat)
                        in_module = any(PAT.match(line) for line in source_lines)
                    if in_module:
                        valname = '%s.%s' % (name, valname)
                        self._find(tests, val, valname, module, source_lines,
                                   globs, seen)
Example #45
0
                # Special handling for staticmethod/classmethod.
                if isinstance(val, staticmethod):
                    val = getattr(obj, valname)
                if isinstance(val, classmethod):
                    val = getattr(obj, valname).im_func

                # Recurse to methods, properties, and nested classes.
                if (inspect.isfunction(val) or
                     inspect.isclass(val) or
                     isinstance(val, property)):
                    in_module = self._from_module(module, val)
                    if not in_module:
                        # "double check" again
                        pat = r'\s*(def|class)\s+%s\s*\(' % valname
                        PAT = pre.compile(pat)
                        in_module = any(PAT.match(line) for line in source_lines)
                    if in_module:
                        valname = '%s.%s' % (name, valname)
                        self._find(tests, val, valname, module, source_lines,
                                   globs, seen)

    def _get_test(self, obj, name, module, globs, source_lines):
        """
        Return a DocTest for the given object, if it defines a docstring;
        otherwise, return None.
        """
        # Extract the object's docstring.  If it doesn't have one,
        # then return None (no test for this object).
        if isinstance(obj, basestring):
            docstring = obj
        else:
Example #46
0
def denester(nested):
    """
    Denests a list of expressions that contain nested square roots.
    This method should not be called directly - use 'denest' instead.
    This algorithm is based on <http://www.almaden.ibm.com/cs/people/fagin/symb85.pdf>.

    It is assumed that all of the elements of 'nested' share the same
    bottom-level radicand. (This is stated in the paper, on page 177, in
    the paragraph immediately preceding the algorithm.)

    When evaluating all of the arguments in parallel, the bottom-level
    radicand only needs to be denested once. This means that calling
    denester with x arguments results in a recursive invocation with x+1
    arguments; hence denester has polynomial complexity.

    However, if the arguments were evaluated separately, each call would
    result in two recursive invocations, and the algorithm would have
    exponential complexity.

    This is discussed in the paper in the middle paragraph of page 179.
    """
    if all((n**2).is_Number
           for n in nested):  #If none of the arguments are nested
        for f in subsets(len(nested)):  #Test subset 'f' of nested
            p = prod(nested[i]**2 for i in range(len(f)) if f[i]).expand()
            if 1 in f and f.count(1) > 1 and f[-1]: p = -p
            if sqrt(p).is_Number:
                return sqrt(
                    p), f  #If we got a perfect square, return its square root.
        return nested[-1], [0] * len(
            nested
        )  #Otherwise, return the radicand from the previous invocation.
    else:
        a, b, r, R = Wild('a'), Wild('b'), Wild('r'), None
        values = [expr.match(sqrt(a + b * sqrt(r))) for expr in nested]
        for v in values:
            if r in v:  #Since if b=0, r is not defined
                if R is not None:
                    assert R == v[r]  #All the 'r's should be the same.
                else:
                    R = v[r]
        d, f = denester([
            sqrt((v[a]**2).expand() - (R * v[b]**2).expand()) for v in values
        ] + [sqrt(R)])
        if not any([f[i] for i in range(len(nested))
                    ]):  #If f[i]=0 for all i < len(nested)
            v = values[-1]
            return sqrt(v[a] + v[b] * d), f
        else:
            v = prod(nested[i]**2 for i in range(len(nested))
                     if f[i]).expand().match(a + b * sqrt(r))
            if 1 in f and f.index(1) < len(nested) - 1 and f[len(nested) - 1]:
                v[a] = -1 * v[a]
                v[b] = -1 * v[b]
            if not f[len(nested)]:  #Solution denests with square roots
                return (sqrt((v[a] + d).expand() / 2) + sign(v[b]) * sqrt(
                    (v[b]**2 * R / (2 * (v[a] + d))).expand())).expand(), f
            else:  #Solution requires a fourth root
                FR, s = (R.expand()**Rational(
                    1, 4)), sqrt((v[b] * R).expand() + d)
                return (s / (sqrt(2) * FR) + v[a] * FR /
                        (sqrt(2) * s)).expand(), f
Example #47
0
    def update(G, B, ih):
        # update G using the set of critical pairs B and h
        # [BW] page 230
        h = f[ih]
        mh = sdp_LM(h, u)

        # filter new pairs (h, g), g in G
        C = G.copy()
        D = set()

        while C:
            # select a pair (h, g) by popping an element from C
            ig = C.pop()
            g = f[ig]
            mg = sdp_LM(g, u)
            LCMhg = monomial_lcm(mh, mg)

            def lcm_divides(ip):
                # LCM(LM(h), LM(p)) divides LCM(LM(h), LM(g))
                m = monomial_lcm(mh, sdp_LM(f[ip], u))
                return monomial_div(LCMhg, m)

            # HT(h) and HT(g) disjoint: mh*mg == LCMhg
            if monomial_mul(mh, mg) == LCMhg or (not any(
                    lcm_divides(ipx)
                    for ipx in C) and not any(lcm_divides(pr[1]) for pr in D)):
                D.add((ih, ig))

        E = set()

        while D:
            # select h, g from D (h the same as above)
            ih, ig = D.pop()
            mg = sdp_LM(f[ig], u)
            LCMhg = monomial_lcm(mh, mg)

            if not monomial_mul(mh, mg) == LCMhg:
                E.add((ih, ig))

        # filter old pairs
        B_new = set()

        while B:
            # select g1, g2 from B (-> CP)
            ig1, ig2 = B.pop()
            mg1 = sdp_LM(f[ig1], u)
            mg2 = sdp_LM(f[ig2], u)
            LCM12 = monomial_lcm(mg1, mg2)

            # if HT(h) does not divide lcm(HT(g1), HT(g2))
            if not monomial_div(LCM12, mh) or \
                monomial_lcm(mg1, mh) == LCM12 or \
                monomial_lcm(mg2, mh) == LCM12:
                B_new.add((ig1, ig2))

        B_new |= E

        # filter polynomials
        G_new = set()

        while G:
            ig = G.pop()
            mg = sdp_LM(f[ig], u)

            if not monomial_div(mg, mh):
                G_new.add(ig)

        G_new.add(ih)

        return G_new, B_new
Example #48
0
    def _eval_nseries(self, x, n, logx):
        """
        This function does compute series for multivariate functions,
        but the expansion is always in terms of *one* variable.
        Examples:

        >>> from sympy import atan2, O
        >>> from sympy.abc import x, y
        >>> atan2(x, y).series(x, n=2)
        atan2(0, y) + x/y + O(x**2)
        >>> atan2(x, y).series(y, n=2)
        atan2(x, 0) - y/x + O(y**2)

        This function also computes asymptotic expansions, if necessary
        and possible:

        >>> from sympy import loggamma
        >>> loggamma(1/x)._eval_nseries(x,0,None)
        log(x)/2 - log(x)/x - 1/x + O(1)
        """
        if self.func.nargs is None:
            raise NotImplementedError('series for user-defined \
functions are not supported.')
        args = self.args
        args0 = [t.limit(x, 0) for t in args]
        if any([t.is_bounded == False for t in args0]):
            from sympy import Dummy, oo, zoo, nan
            a = [t.compute_leading_term(x, logx=logx) for t in args]
            a0 = [t.limit(x, 0) for t in a]
            if any ([t.has(oo, -oo, zoo, nan) for t in a0]):
               return self._eval_aseries(n, args0, x, logx)._eval_nseries(x, n, logx)
            # Careful: the argument goes to oo, but only logarithmically so. We
            # are supposed to do a power series expansion "around the
            # logarithmic term". e.g.
            #      f(1+x+log(x))
            #     -> f(1+logx) + x*f'(1+logx) + O(x**2)
            # where 'logx' is given in the argument
            a = [t._eval_nseries(x, n, logx) for t in args]
            z = [r - r0 for (r, r0) in zip(a, a0)]
            p = [Dummy() for t in z]
            q = []
            v = None
            for ai, zi, pi in zip(a0, z, p):
                if zi.has(x):
                    if v is not None: raise NotImplementedError
                    q.append(ai + pi)
                    v = pi
                else:
                    q.append(ai)
            e1 = self.func(*q)
            if v is None:
                return e1
            s = e1._eval_nseries(v, n, logx)
            o = s.getO()
            s = s.removeO()
            s = s.subs(v, zi).expand() + C.Order(o.expr.subs(v, zi), x)
            return s
        if (self.func.nargs == 1 and args0[0]) or self.func.nargs > 1:
            e = self
            e1 = e.expand()
            if e == e1:
                #for example when e = sin(x+1) or e = sin(cos(x))
                #let's try the general algorithm
                term = e.subs(x, S.Zero)
                if term.is_bounded is False or term is S.NaN:
                    raise PoleError("Cannot expand %s around 0" % (self))
                series = term
                fact = S.One
                for i in range(n-1):
                    i += 1
                    fact *= Rational(i)
                    e = e.diff(x)
                    subs = e.subs(x, S.Zero)
                    if subs is S.NaN:
                        # try to evaluate a limit if we have to
                        subs = e.limit(x, S.Zero)
                    if subs.is_bounded is False:
                        raise PoleError("Cannot expand %s around 0" % (self))
                    term = subs*(x**i)/fact
                    term = term.expand()
                    series += term
                return series + C.Order(x**n, x)
            return e1.nseries(x, n=n, logx=logx)
        arg = self.args[0]
        l = []
        g = None
        for i in xrange(n+2):
            g = self.taylor_term(i, arg, g)
            g = g.nseries(x, n=n, logx=logx)
            l.append(g)
        return Add(*l) + C.Order(x**n, x)
Example #49
0
    def doit(self, **hints):
        if not hints.get('integrals', True):
            return self

        deep = hints.get('deep', True)

        # check for the trivial case of equal upper and lower limits
        if self.is_zero:
            return S.Zero

        # now compute and check the function
        function = self.function
        if deep:
            function = function.doit(**hints)

        if function.is_zero:
            return S.Zero

        # There is no trivial answer, so continue

        undone_limits = []
        ulj = set() # free symbols of any undone limits' upper and lower limits
        for xab in self.limits:
            # compute uli, the free symbols in the
            # Upper and Lower limits of limit I
            if len(xab) == 1:
                uli = set(xab[:1])
            elif len(xab) == 2:
                uli = xab[1].free_symbols
            elif len(xab) == 3:
                uli = xab[1].free_symbols.union(xab[2].free_symbols)
            # this integral can be done as long as there is no blocking
            # limit that has been undone. An undone limit is blocking if
            # it contains an integration variable that is in this limit's
            # upper or lower free symbols or vice versa
            if xab[0] in ulj or any(v[0] in uli for v in undone_limits):
                undone_limits.append(xab)
                ulj.update(uli)
                continue

            antideriv = self._eval_integral(function, xab[0])

            if antideriv is None:
                undone_limits.append(xab)
            else:
                if len(xab) == 1:
                    function = antideriv
                else:
                    if len(xab) == 3:
                        x, a, b = xab
                    if len(xab) == 2:
                        x, b = xab
                        a = None

                    if deep:
                        if isinstance(a, Basic):
                            a = a.doit(**hints)
                        if isinstance(b, Basic):
                            b = b.doit(**hints)

                    if antideriv.is_Poly:
                        gens = list(antideriv.gens)
                        gens.remove(x)

                        antideriv = antideriv.as_basic()

                        function = antideriv._eval_interval(x, a, b)
                        function = Poly(function, *gens)
                    else:
                        function = antideriv._eval_interval(x, a, b)

        if undone_limits:
            return self.new(*([function] + undone_limits))
        return function
Example #50
0
def solve(f, *symbols, **flags):
    """
    Algebraically solves equations and systems of equations.

        Currently supported are:
            - univariate polynomial,
            - transcendental
            - piecewise combinations of the above
            - systems of linear and polynomial equations
            - sytems containing relational expressions.

        Input is formed as:
            f
                - a single Expr or Poly that must be zero,
                - an Equality
                - a Relational expression or boolean
                - iterable of one or more of the above

            symbols (Symbol, Function or Derivative) specified as
                - none given (all free symbols will be used)
                - single symbol
                - denested list of symbols
                  e.g. solve(f, x, y)
                - ordered iterable of symbols
                  e.g. solve(f, [x, y])

            flags
                - ``simplified``, when False, will not simplify solutions
                                 (default=True except for polynomials of
                                  order 3 or greater)

        The output varies according to the input and can be seen by example:

            >>> from sympy import solve, Poly, Eq, Function, exp
            >>> from sympy.abc import x, y, z, a, b

            o boolean or univariate Relational

                >>> solve(x < 3)
                And(im(x) == 0, re(x) < 3)

            o single expression and single symbol that is in the expression

                >>> solve(x - y, x)
                [y]
                >>> solve(x - 3, x)
                [3]
                >>> solve(Eq(x, 3), x)
                [3]
                >>> solve(Poly(x - 3), x)
                [3]
                >>> solve(x**2 - y**2, x)
                [y, -y]
                >>> solve(x**4 - 1, x)
                [1, -1, -I, I]

            o single expression with no symbol that is in the expression

                >>> solve(3, x)
                []
                >>> solve(x - 3, y)
                []

            o when no symbol is given then all free symbols will be used
              and sorted with default_sort_key and the result will be the
              same as above as if those symbols had been supplied

                >>> solve(x - 3)
                [3]
                >>> solve(x**2 - y**2)
                [y, -y]

            o when a Function or Derivative is given as a symbol, it is isolated
              algebraically and an implicit solution may be obtained

                >>> f = Function('f')
                >>> solve(f(x) - x, f(x))
                [x]
                >>> solve(f(x).diff(x) - f(x) - x, f(x).diff(x))
                [x + f(x)]

            o single expression and more than 1 symbol

                when there is a linear solution
                    >>> solve(x - y**2, x, y)
                    {x: y**2}
                    >>> solve(x**2 - y, x, y)
                    {y: x**2}

                when undetermined coefficients are identified
                    that are linear
                        >>> solve((a + b)*x - b + 2, a, b)
                        {a: -2, b: 2}

                    that are nonlinear
                        >>> solve((a + b)*x - b**2 + 2, a, b)
                        [(-2**(1/2), 2**(1/2)), (2**(1/2), -2**(1/2))]

                if there is no linear solution then the first successful
                attempt for a nonlinear solution will be returned
                    >>> solve(x**2 - y**2, x, y)
                    [y, -y]
                    >>> solve(x**2 - y**2/exp(x), x, y)
                    [x*exp(x/2), -x*exp(x/2)]

            o iterable of one or more of the above

                involving relationals or bools
                    >>> solve([x < 3, x - 2])
                    And(im(x) == 0, re(x) == 2)
                    >>> solve([x > 3, x - 2])
                    False

                when the system is linear
                    with a solution
                        >>> solve([x - 3], x)
                        {x: 3}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y)
                        {x: -3, y: 1}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y, z)
                        {x: -3, y: 1}
                        >>> solve((x + 5*y - 2, -3*x + 6*y - z), z, x, y)
                        {x: -5*y + 2, z: 21*y - 6}

                    without a solution
                        >>> solve([x + 3, x - 3])

                when the system is not linear
                    >>> solve([x**2 + y -2, y**2 - 4], x, y)
                    [(-2, -2), (0, 2), (0, 2), (2, -2)]

                Warning: there is a possibility of obtaining ambiguous results
                if no symbols are given for a nonlinear system of equations or
                are given as a set since the symbols are not presently reported
                with the solution. A warning will be issued in this situation.
                    >>> solve([x - 2, x**2 + y])
                    <BLANKLINE>
                        For nonlinear systems of equations, symbols should be
                        given as a list so as to avoid ambiguity in the results.
                        solve sorted the symbols as [x, y]
                    [(2, -4)]

                    >>> solve([x - 2, x**2 + f(x)], set([f(x), x]))
                    <BLANKLINE>
                        For nonlinear systems of equations, symbols should be
                        given as a list so as to avoid ambiguity in the results.
                        solve sorted the symbols as [x, f(x)]
                    [(2, -4)]

       See also:
          rsolve() for solving recurrence relationships
          dsolve() for solving differential equations

    """

    # make f and symbols into lists of sympified quantities
    # keeping track of how f was passed since if it is a list
    # a dictionary of results will be returned.
    ###########################################################################
    def sympified_list(w):
        return map(sympify, iff(iterable(w), w, [w]))

    bare_f = not iterable(f)
    ordered_symbols = (symbols and symbols[0] and
                       (isinstance(symbols[0], Symbol)
                        or ordered_iter(symbols[0], include=GeneratorType)))
    f, symbols = (sympified_list(w) for w in [f, symbols])

    # preprocess equation(s)
    ###########################################################################
    for i, fi in enumerate(f):
        if isinstance(fi, Equality):
            f[i] = fi.lhs - fi.rhs
        elif isinstance(fi, Poly):
            f[i] = fi.as_expr()
        elif isinstance(fi, bool) or fi.is_Relational:
            return reduce_inequalities(f, assume=flags.get('assume'))
        # Any embedded piecewise functions need to be brought out to the
        # top level so that the appropriate strategy gets selected.
        f[i] = piecewise_fold(f[i])

    # preprocess symbol(s)
    ###########################################################################
    if not symbols:
        # get symbols from equations or supply dummy symbols so solve(3) behaves
        # like solve(3, x).
        symbols = set([])
        for fi in f:
            symbols |= fi.free_symbols or set([Dummy()])
        ordered_symbols = False
    elif len(symbols) == 1 and iterable(symbols[0]):
        symbols = symbols[0]
    if not ordered_symbols:
        # we do this to make the results returned canonical in case f
        # contains a system of nonlinear equations; all other cases should
        # be unambiguous
        symbols = sorted(symbols, key=lambda i: i.sort_key())

    # we can solve for Function and Derivative instances by replacing them
    # with Dummy symbols
    symbols_new = []
    symbol_swapped = False
    symbols_passed = list(symbols)

    for i, s in enumerate(symbols):
        if s.is_Symbol:
            s_new = s
        elif s.is_Function:
            symbol_swapped = True
            s_new = Dummy('F%d' % i)
        elif s.is_Derivative:
            symbol_swapped = True
            s_new = Dummy('D%d' % i)
        else:
            msg = 'expected Symbol, Function or Derivative but got %s'
            raise TypeError(msg % type(s))
        symbols_new.append(s_new)

    if symbol_swapped:
        swap_back_dict = dict(zip(symbols_new, symbols))
        swap_dict = zip(symbols, symbols_new)
        f = [fi.subs(swap_dict) for fi in f]
        symbols = symbols_new

    #
    # try to get a solution
    ###########################################################################
    if bare_f:
        # pass f the way it was passed to solve; if it wasn't a list then
        # a list of solutions will be returned, otherwise a dictionary is
        # going to be returned
        f = f[0]
    solution = _solve(f, *symbols, **flags)

    #
    # postprocessing
    ###########################################################################
    # Restore original Functions and Derivatives if a dictionary is returned.
    # This is not necessary for
    #   - the single equation, single unknown case
    #     since the symbol will have been removed from the solution;
    #   - the nonlinear poly_system since that only support zero-dimensional
    #     systems and those results come back as a list
    if symbol_swapped and type(solution) is dict:
        solution = dict([(swap_back_dict[k], v.subs(swap_back_dict))
                         for k, v in solution.iteritems()])
    # warn if ambiguous results are being obtained
    # XXX agree on how to make this unambiguous
    # see issue 2405 for logic in how Polys chooses ordering and
    # for discussion of what to return see http://groups.google.com/group/sympy
    #                           Apr 18, 2011 posting 'using results from solve'
    elif (not ordered_symbols and len(symbols) > 1 and solution
          and ordered_iter(solution) and ordered_iter(solution[0])
          and any(len(set(s)) > 1 for s in solution)):
        msg = ('\n\tFor nonlinear systems of equations, symbols should be' +
               '\n\tgiven as a list so as to avoid ambiguity in the results.' +
               '\n\tsolve sorted the symbols as %s')
        print msg % str(
            bool(symbol_swapped) and list(zip(*swap_dict)[0]) or symbols)
    #
    # done
    ###########################################################################
    return solution
Example #51
0
def solve_linear_system(system, *symbols, **flags):
    """Solve system of N linear equations with M variables, which means
       both Cramer and over defined systems are supported. The possible
       number of solutions is zero, one or infinite. Respectively this
       procedure will return None or dictionary with solutions. In the
       case of over defined system all arbitrary parameters are skipped.
       This may cause situation in with empty dictionary is returned.
       In this case it means all symbols can be assigned arbitrary values.

       Input to this functions is a Nx(M+1) matrix, which means it has
       to be in augmented form. If you are unhappy with such setting
       use 'solve' method instead, where you can input equations
       explicitly. And don't worry about the matrix, this function
       is persistent and will make a local copy of it.

       The algorithm used here is fraction free Gaussian elimination,
       which results, after elimination, in upper-triangular matrix.
       Then solutions are found using back-substitution. This approach
       is more efficient and compact than the Gauss-Jordan method.

       >>> from sympy import Matrix, solve_linear_system
       >>> from sympy.abc import x, y

       Solve the following system:

              x + 4 y ==  2
           -2 x +   y == 14

       >>> system = Matrix(( (1, 4, 2), (-2, 1, 14)))
       >>> solve_linear_system(system, x, y)
       {x: -6, y: 2}

    """
    matrix = system[:, :]
    syms = list(symbols)

    i, m = 0, matrix.cols - 1  # don't count augmentation

    while i < matrix.rows:
        if i == m:
            # an overdetermined system
            if any(matrix[i:, m]):
                return None  # no solutions
            else:
                # remove trailing rows
                matrix = matrix[:i, :]
                break

        if not matrix[i, i]:
            # there is no pivot in current column
            # so try to find one in other columns
            for k in xrange(i + 1, m):
                if matrix[i, k]:
                    break
            else:
                if matrix[i, m]:
                    return None  # no solutions
                else:
                    # zero row or was a linear combination of
                    # other rows so now we can safely skip it
                    matrix.row_del(i)
                    continue

            # we want to change the order of colums so
            # the order of variables must also change
            syms[i], syms[k] = syms[k], syms[i]
            matrix.col_swap(i, k)

        pivot_inv = S.One / matrix[i, i]

        # divide all elements in the current row by the pivot
        matrix.row(i, lambda x, _: x * pivot_inv)

        for k in xrange(i + 1, matrix.rows):
            if matrix[k, i]:
                coeff = matrix[k, i]

                # subtract from the current row the row containing
                # pivot and multiplied by extracted coefficient
                matrix.row(k, lambda x, j: simplify(x - matrix[i, j] * coeff))

        i += 1

    # if there weren't any problems, augmented matrix is now
    # in row-echelon form so we can check how many solutions
    # there are and extract them using back substitution

    simplified = flags.get("simplified", True)

    if len(syms) == matrix.rows:
        # this system is Cramer equivalent so there is
        # exactly one solution to this system of equations
        k, solutions = i - 1, {}

        while k >= 0:
            content = matrix[k, m]

            # run back-substitution for variables
            for j in xrange(k + 1, m):
                content -= matrix[k, j] * solutions[syms[j]]

            if simplified:
                solutions[syms[k]] = simplify(content)
            else:
                solutions[syms[k]] = content

            k -= 1

        return solutions
    elif len(syms) > matrix.rows:
        # this system will have infinite number of solutions
        # dependent on exactly len(syms) - i parameters
        k, solutions = i - 1, {}

        while k >= 0:
            content = matrix[k, m]

            # run back-substitution for variables
            for j in xrange(k + 1, i):
                content -= matrix[k, j] * solutions[syms[j]]

            # run back-substitution for parameters
            for j in xrange(i, m):
                content -= matrix[k, j] * syms[j]

            if simplified:
                solutions[syms[k]] = simplify(content)
            else:
                solutions[syms[k]] = content

            k -= 1

        return solutions
    else:
        return None  # no solutions
Example #52
0
def doctest(*paths, **kwargs):
    """
    Runs doctests in all *py files in the sympy directory which match
    any of the given strings in `paths` or all tests if paths=[].

    Note:
       o paths can be entered in native system format or in unix,
         forward-slash format.
       o files that are on the blacklist can be tested by providing
         their path; they are only excluded if no paths are given.

    Examples:

    >> import sympy

    Run all tests:
    >> sympy.doctest()

    Run one file:
    >> sympy.doctest("sympy/core/basic.py")
    >> sympy.doctest("polynomial.txt")

    Run all tests in sympy/functions/ and some particular file:
    >> sympy.doctest("/functions", "basic.py")

    Run any file having polynomial in its name, doc/src/modules/polynomial.txt,
    sympy\functions\special\polynomials.py, and sympy\polys\polynomial.py:
    >> sympy.doctest("polynomial")
    """
    normal = kwargs.get("normal", False)
    verbose = kwargs.get("verbose", False)
    blacklist = kwargs.get("blacklist", [])
    blacklist.extend([
                    "sympy/thirdparty/pyglet", # segfaults
                    "doc/src/modules/mpmath", # needs to be fixed upstream
                    "sympy/mpmath", # needs to be fixed upstream
                    "doc/src/modules/plotting.txt", # generates live plots
                    "sympy/plotting", # generates live plots
                    "sympy/utilities/compilef.py", # needs tcc
                    "sympy/galgebra/GA.py", # needs numpy
                    "sympy/galgebra/latex_ex.py", # needs numpy
                    "sympy/conftest.py", # needs py.test
                    "sympy/utilities/benchmarking.py", # needs py.test
                    ])
    blacklist = convert_to_native_paths(blacklist)

    r = PyTestReporter(verbose)
    t = SymPyDocTests(r, normal)

    test_files = t.get_test_files('sympy')
    not_blacklisted = [f for f in test_files
                         if not any(b in f for b in blacklist)]
    if len(paths) == 0:
        t._tests.extend(not_blacklisted)
    else:
        # take only what was requested...but not blacklisted items
        # and allow for partial match anywhere or fnmatch of name
        paths = convert_to_native_paths(paths)
        matched = []
        for f in not_blacklisted:
            basename = os.path.basename(f)
            for p in paths:
                if p in f or fnmatch(basename, p):
                    matched.append(f)
                    break
        t._tests.extend(matched)

    # run the tests and record the result for this *py portion of the tests
    if t._tests:
        doc_tests_succeeded = t.test()
    else:
        doc_tests_succeeded = True

    # test *txt files only if we are running python newer than 2.4
    if sys.version_info[:2] > (2,4):

        # N.B.
        # --------------------------------------------------------------------
        # Here we test *.txt files at or below doc/src. Code from these must
        # be self supporting in terms of imports since there is no importing
        # of necessary modules by doctest.testfile. If you try to pass *.py
        # files through this they might fail because they will lack the needed
        # imports and smarter parsing that can be done with source code.
        #
        test_files = t.get_test_files('doc/src', '*.txt', init_only=False)
        test_files.sort()

        not_blacklisted = [f for f in test_files
                             if not any(b in f for b in blacklist)]

        if len(paths) == 0:
            matched = not_blacklisted
        else:
            # Take only what was requested as long as it's not on the blacklist.
            # Paths were already made native in *py tests so don't repeat here.
            # There's no chance of having a *py file slip through since we
            # only have *txt files in test_files.
            matched =  []
            for f in not_blacklisted:
                basename = os.path.basename(f)
                for p in paths:
                    if p in f or fnmatch(basename, p):
                        matched.append(f)
                        break

        setup_pprint()
        for txt_file in matched:
            if not os.path.isfile(txt_file):
                continue
            old_displayhook = sys.displayhook
            try:
                out = pdoctest.testfile(txt_file, module_relative=False,
                        optionflags=pdoctest.ELLIPSIS | \
                        pdoctest.NORMALIZE_WHITESPACE)
            finally:
                # make sure we return to the original displayhook in case some
                # doctest has changed that
                sys.displayhook = old_displayhook
            print "Testing ", txt_file
            print "Failed %s, tested %s" % out
            if out[0] != 0:
                doc_tests_succeeded = False

    # the doctests for *py will have printed this message already if there was
    # a failure, so now only print it if there was intervening reporting by
    # testing the *txt.
    if matched and not doc_tests_succeeded:
        print("DO *NOT* COMMIT!")
    return doc_tests_succeeded
Example #53
0
            for valname, val in obj.__dict__.items():
                # Special handling for staticmethod/classmethod.
                if isinstance(val, staticmethod):
                    val = getattr(obj, valname)
                if isinstance(val, classmethod):
                    val = getattr(obj, valname).im_func

                # Recurse to methods, properties, and nested classes.
                if (inspect.isfunction(val) or inspect.isclass(val)
                        or isinstance(val, property)):
                    in_module = self._from_module(module, val)
                    if not in_module:
                        # "double check" again
                        pat = r'\s*(def|class)\s+%s\s*\(' % valname
                        PAT = pre.compile(pat)
                        in_module = any(
                            PAT.match(line) for line in source_lines)
                    if in_module:
                        valname = '%s.%s' % (name, valname)
                        self._find(tests, val, valname, module, source_lines,
                                   globs, seen)

    def _get_test(self, obj, name, module, globs, source_lines):
        """
        Return a DocTest for the given object, if it defines a docstring;
        otherwise, return None.
        """
        # Extract the object's docstring.  If it doesn't have one,
        # then return None (no test for this object).
        if isinstance(obj, basestring):
            docstring = obj
        else:
Example #54
0
def solve(f, *symbols, **flags):
    """Solves equations and systems of equations.

       Currently supported are univariate polynomial and transcendental
       equations and systems of linear and polynomial equations.  Input
       is formed as a single expression or an equation,  or an iterable
       container in case of an equation system.  The type of output may
       vary and depends heavily on the input. For more details refer to
       more problem specific functions.

       By default all solutions are simplified to make the output more
       readable. If this is not the expected behavior,  eg. because of
       speed issues, set simplified=False in function arguments.

       To solve equations and systems of equations of other kind, eg.
       recurrence relations of differential equations use rsolve() or
       dsolve() functions respectively.

       >>> from sympy import *
       >>> x,y = symbols('xy')

       Solve a polynomial equation:

       >>> solve(x**4-1, x)
       [1, -1, -I, I]

       Solve a linear system:

       >>> solve((x+5*y-2, -3*x+6*y-15), x, y)
       {x: -3, y: 1}

    """
    if not symbols:
        raise ValueError('no symbols were given')

    if len(symbols) == 1:
        if isinstance(symbols[0], (list, tuple, set)):
            symbols = symbols[0]

    symbols = map(sympify, symbols)

    if any(not s.is_Symbol for s in symbols):
        raise TypeError('not a Symbol')

    if not isinstance(f, (tuple, list, set)):
        f = sympify(f)

        if isinstance(f, Equality):
            f = f.lhs - f.rhs

        if len(symbols) != 1:
            raise NotImplementedError('multivariate equation')

        symbol = symbols[0]

        strategy = guess_solve_strategy(f, symbol)

        if strategy == GS_POLY:
            poly = f.as_poly(symbol)
            assert poly is not None
            result = roots(poly, cubics=True, quartics=True).keys()

        elif strategy == GS_RATIONAL:
            P, Q = f.as_numer_denom()
            #TODO: check for Q != 0
            return solve(P, symbol, **flags)

        elif strategy == GS_POLY_CV_1:
            # we must search for a suitable change of variable
            # collect exponents
            exponents_denom = list()
            args = list(f.args)
            if isinstance(f, Add):
                for arg in args:
                    if isinstance(arg, Pow):
                        exponents_denom.append(arg.exp.q)
                    elif isinstance(arg, Mul):
                        for mul_arg in arg.args:
                            if isinstance(mul_arg, Pow):
                                exponents_denom.append(mul_arg.exp.q)
            elif isinstance(f, Mul):
                for mul_arg in args:
                    if isinstance(mul_arg, Pow):
                        exponents_denom.append(mul_arg.exp.q)

            assert len(exponents_denom) > 0
            if len(exponents_denom) == 1:
                m = exponents_denom[0]
            else:
                # get the GCD of the denominators
                m = ilcm(*exponents_denom)
            # x -> y**m.
            # we assume positive for simplification purposes
            t = Symbol('t', positive=True, dummy=True)
            f_ = f.subs(symbol, t**m)
            if guess_solve_strategy(f_, t) != GS_POLY:
                raise TypeError(
                    "Could not convert to a polynomial equation: %s" % f_)
            cv_sols = solve(f_, t)
            result = list()
            for sol in cv_sols:
                result.append(sol**(S.One / m))

        elif strategy == GS_POLY_CV_2:
            m = 0
            args = list(f.args)
            if isinstance(f, Add):
                for arg in args:
                    if isinstance(arg, Pow):
                        m = min(m, arg.exp)
                    elif isinstance(arg, Mul):
                        for mul_arg in arg.args:
                            if isinstance(mul_arg, Pow):
                                m = min(m, mul_arg.exp)
            elif isinstance(f, Mul):
                for mul_arg in args:
                    if isinstance(mul_arg, Pow):
                        m = min(m, mul_arg.exp)
            f1 = simplify(f * symbol**(-m))
            result = solve(f1, symbol)
            # TODO: we might have introduced unwanted solutions
            # when multiplied by x**-m

        elif strategy == GS_TRASCENDENTAL:
            #a, b = f.as_numer_denom()
            # Let's throw away the denominator for now. When we have robust
            # assumptions, it should be checked, that for the solution,
            # b!=0.
            result = tsolve(f, *symbols)
        elif strategy == -1:
            raise Exception('Could not parse expression %s' % f)
        else:
            raise NotImplementedError(
                "No algorithms where implemented to solve equation %s" % f)

        if flags.get('simplified', True):
            return map(simplify, result)
        else:
            return result
    else:
        if not f:
            return {}
        else:
            polys = []

            for g in f:
                g = sympify(g)

                if isinstance(g, Equality):
                    g = g.lhs - g.rhs

                poly = g.as_poly(*symbols)

                if poly is not None:
                    polys.append(poly)
                else:
                    raise NotImplementedError

            if all(p.is_linear for p in polys):
                n, m = len(f), len(symbols)
                matrix = zeros((n, m + 1))

                for i, poly in enumerate(polys):
                    for coeff, monom in poly.iter_terms():
                        try:
                            j = list(monom).index(1)
                            matrix[i, j] = coeff
                        except ValueError:
                            matrix[i, m] = -coeff

                return solve_linear_system(matrix, *symbols, **flags)
            else:
                return solve_poly_system(polys)
Example #55
0
def _construct_composite(coeffs, opt):
    """Handle composite domains, e.g.: ZZ[X], QQ[X], ZZ(X), QQ(X). """
    numers, denoms = [], []

    for coeff in coeffs:
        numer, denom = coeff.as_numer_denom()

        numers.append(numer)
        denoms.append(denom)

    polys, gens = parallel_dict_from_basic(numers + denoms)  # XXX: sorting

    if any(gen.is_number for gen in gens):
        return None  # generators are number-like so lets better use EX

    n = len(gens)
    k = len(polys) // 2

    numers = polys[:k]
    denoms = polys[k:]

    if opt.field:
        fractions = True
    else:
        fractions, zeros = False, (0,) * n

        for denom in denoms:
            if len(denom) > 1 or zeros not in denom:
                fractions = True
                break

    result = []

    if not fractions:
        coeffs = set([])

        for numer, denom in zip(numers, denoms):
            denom = denom[zeros]

            for monom, coeff in numer.iteritems():
                coeff /= denom
                coeffs.add(coeff)
                numer[monom] = coeff

        rationals, reals = False, False

        for coeff in coeffs:
            if coeff.is_Rational:
                if not coeff.is_Integer:
                    rationals = True
            elif coeff.is_Real:
                reals = True
                break

        if reals:
            ground = RR
        elif rationals:
            ground = QQ
        else:
            ground = ZZ

        domain = ground.poly_ring(*gens)

        for numer in numers:
            for monom, coeff in numer.iteritems():
                numer[monom] = ground.from_sympy(coeff)

            result.append(domain(numer))
    else:
        domain = ZZ.frac_field(*gens)

        for numer, denom in zip(numers, denoms):
            for monom, coeff in numer.iteritems():
                numer[monom] = ZZ.from_sympy(coeff)

            for monom, coeff in denom.iteritems():
                denom[monom] = ZZ.from_sympy(coeff)

            result.append(domain((numer, denom)))

    return domain, result
Example #56
0
def solve(f, *symbols, **flags):
    """Solves equations and systems of equations.

       Currently supported are univariate polynomial, transcendental
       equations, piecewise combinations thereof and systems of linear
       and polynomial equations.  Input is formed as a single expression
       or an equation,  or an iterable container in case of an equation
       system.  The type of output may vary and depends heavily on the
       input. For more details refer to more problem specific functions.

       By default all solutions are simplified to make the output more
       readable. If this is not the expected behavior (e.g., because of
       speed issues) set simplified=False in function arguments.

       To solve equations and systems of equations like recurrence relations
       or differential equations, use rsolve() or dsolve(), respectively.

       >>> from sympy import I, solve
       >>> from sympy.abc import x, y

       Solve a polynomial equation:

       >>> solve(x**4-1, x)
       [1, -1, -I, I]

       Solve a linear system:

       >>> solve((x+5*y-2, -3*x+6*y-15), x, y)
       {x: -3, y: 1}

    """
    def sympit(w):
        return map(sympify, iff(isinstance(w,(list, tuple, set)), w, [w]))
    # make f and symbols into lists of sympified quantities
    # keeping track of how f was passed since if it is a list
    # a dictionary of results will be returned.
    bare_f = not isinstance(f, (list, tuple, set))
    f, symbols = (sympit(w) for w in [f, symbols])

    if any(isinstance(fi, bool) or (fi.is_Relational and not fi.is_Equality) for fi in f):
        return reduce_inequalities(f, assume=flags.get('assume'))

    for i, fi in enumerate(f):
        if fi.is_Equality:
            f[i] = fi.lhs - fi.rhs

    if not symbols:
        #get symbols from equations or supply dummy symbols since
        #solve(3,x) returns []...though it seems that it should raise some sort of error TODO
        symbols = set([])
        for fi in f:
            symbols |= fi.atoms(Symbol) or set([Dummy('x')])
        symbols = list(symbols)

    if bare_f:
        f=f[0]
    if len(symbols) == 1:
        if isinstance(symbols[0], (list, tuple, set)):
            symbols = symbols[0]

    result = list()

    # Begin code handling for Function and Derivative instances
    # Basic idea:  store all the passed symbols in symbols_passed, check to see
    # if any of them are Function or Derivative types, if so, use a dummy
    # symbol in their place, and set symbol_swapped = True so that other parts
    # of the code can be aware of the swap.  Once all swapping is done, the
    # continue on with regular solving as usual, and swap back at the end of
    # the routine, so that whatever was passed in symbols is what is returned.
    symbols_new = []
    symbol_swapped = False

    symbols_passed = list(symbols)

    for i, s in enumerate(symbols):
        if s.is_Symbol:
            s_new = s
        elif s.is_Function:
            symbol_swapped = True
            s_new = Dummy('F%d' % i)
        elif s.is_Derivative:
            symbol_swapped = True
            s_new = Dummy('D%d' % i)
        else:
            raise TypeError('not a Symbol or a Function')
        symbols_new.append(s_new)

        if symbol_swapped:
            swap_back_dict = dict(zip(symbols_new, symbols))
    # End code for handling of Function and Derivative instances

    if not isinstance(f, (tuple, list, set)):

        # Create a swap dictionary for storing the passed symbols to be solved
        # for, so that they may be swapped back.
        if symbol_swapped:
            swap_dict = zip(symbols, symbols_new)
            f = f.subs(swap_dict)
            symbols = symbols_new

        # Any embedded piecewise functions need to be brought out to the
        # top level so that the appropriate strategy gets selected.
        f = piecewise_fold(f)

        if len(symbols) != 1:
            result = {}
            for s in symbols:
                result[s] = solve(f, s, **flags)
            if flags.get('simplified', True):
                for s, r in result.items():
                    result[s] = map(simplify, r)
            return result

        symbol = symbols[0]
        strategy = guess_solve_strategy(f, symbol)

        if strategy == GS_POLY:
            poly = f.as_poly( symbol )
            if poly is None:
                raise NotImplementedError("Cannot solve equation " + str(f) + " for "
                    + str(symbol))
            # for cubics and quartics, if the flag wasn't set, DON'T do it
            # by default since the results are quite long. Perhaps one could
            # base this decision on a certain crtical length of the roots.
            if poly.degree > 2:
                flags['simplified'] = flags.get('simplified', False)
            result = roots(poly, cubics=True, quartics=True).keys()

        elif strategy == GS_RATIONAL:
            P, Q = f.as_numer_denom()
            #TODO: check for Q != 0
            result = solve(P, symbol, **flags)

        elif strategy == GS_POLY_CV_1:
            args = list(f.args)
            if isinstance(f, Add):
                # we must search for a suitable change of variable
                # collect exponents
                exponents_denom = list()
                for arg in args:
                    if isinstance(arg, Pow):
                        exponents_denom.append(arg.exp.q)
                    elif isinstance(arg, Mul):
                        for mul_arg in arg.args:
                            if isinstance(mul_arg, Pow):
                                exponents_denom.append(mul_arg.exp.q)
                assert len(exponents_denom) > 0
                if len(exponents_denom) == 1:
                    m = exponents_denom[0]
                else:
                    # get the LCM of the denominators
                    m = reduce(ilcm, exponents_denom)
                # x -> y**m.
                # we assume positive for simplification purposes
                t = Dummy('t', positive=True)
                f_ = f.subs(symbol, t**m)
                if guess_solve_strategy(f_, t) != GS_POLY:
                    raise NotImplementedError("Could not convert to a polynomial equation: %s" % f_)
                cv_sols = solve(f_, t)
                for sol in cv_sols:
                    result.append(sol**m)

            elif isinstance(f, Mul):
                for mul_arg in args:
                    result.extend(solve(mul_arg, symbol))

        elif strategy == GS_POLY_CV_2:
            m = 0
            args = list(f.args)
            if isinstance(f, Add):
                for arg in args:
                    if isinstance(arg, Pow):
                        m = min(m, arg.exp)
                    elif isinstance(arg, Mul):
                        for mul_arg in arg.args:
                            if isinstance(mul_arg, Pow):
                                m = min(m, mul_arg.exp)
            elif isinstance(f, Mul):
                for mul_arg in args:
                    if isinstance(mul_arg, Pow):
                        m = min(m, mul_arg.exp)
            f1 = simplify(f*symbol**(-m))
            result = solve(f1, symbol)
            # TODO: we might have introduced unwanted solutions
            # when multiplied by x**-m

        elif strategy == GS_PIECEWISE:
            result = set()
            for expr, cond in f.args:
                candidates = solve(expr, *symbols)
                if isinstance(cond, bool) or cond.is_Number:
                    if not cond:
                        continue

                    # Only include solutions that do not match the condition
                    # of any of the other pieces.
                    for candidate in candidates:
                        matches_other_piece = False
                        for other_expr, other_cond in f.args:
                            if isinstance(other_cond, bool) \
                               or other_cond.is_Number:
                                continue
                            if bool(other_cond.subs(symbol, candidate)):
                                matches_other_piece = True
                                break
                        if not matches_other_piece:
                            result.add(candidate)
                else:
                    for candidate in candidates:
                        if bool(cond.subs(symbol, candidate)):
                            result.add(candidate)

            result = list(result)

        elif strategy == GS_TRANSCENDENTAL:
            #a, b = f.as_numer_denom()
            # Let's throw away the denominator for now. When we have robust
            # assumptions, it should be checked, that for the solution,
            # b!=0.
            result = tsolve(f, *symbols)
        elif strategy == -1:
            raise ValueError('Could not parse expression %s' % f)
        else:
            raise NotImplementedError("No algorithms are implemented to solve equation %s" % f)

        # This symbol swap should not be necessary for the single symbol case: if you've
        # solved for the symbol the it will not appear in the solution. Right now, however
        # ode's are getting solutions for solve (even though they shouldn't be -- see the
        # swap_back test in test_solvers).
        if symbol_swapped:
            result = [ri.subs(swap_back_dict) for ri in result]

        if flags.get('simplified', True) and strategy != GS_RATIONAL:
            return map(simplify, result)
        else:
            return result
    else:
        if not f:
            return {}
        else:
            # Create a swap dictionary for storing the passed symbols to be
            # solved for, so that they may be swapped back.
            if symbol_swapped:
                swap_dict = zip(symbols, symbols_new)
                f = [fi.subs(swap_dict) for fi in f]
                symbols = symbols_new

            polys = []

            for g in f:

                poly = g.as_poly(*symbols)

                if poly is not None:
                    polys.append(poly)
                else:
                    raise NotImplementedError()

            if all(p.is_linear for p in polys):
                n, m = len(f), len(symbols)
                matrix = zeros((n, m + 1))

                for i, poly in enumerate(polys):
                    for monom, coeff in poly.terms():
                        try:
                            j = list(monom).index(1)
                            matrix[i, j] = coeff
                        except ValueError:
                            matrix[i, m] = -coeff

                soln = solve_linear_system(matrix, *symbols, **flags)
            else:
                soln = solve_poly_system(polys)

            # Use swap_dict to ensure we return the same type as what was
            # passed
            if symbol_swapped:
                if isinstance(soln, dict):
                    res = {}
                    for k in soln.keys():
                        res.update({swap_back_dict[k]: soln[k]})
                    return res
                else:
                    return soln
            else:
                return soln