Ejemplo n.º 1
0
    def eval(cls, x, k):
        x = sympify(x)
        k = sympify(k)

        if x is S.NaN:
            return S.NaN
        elif k.is_Integer:
            if k is S.NaN:
                return S.NaN
            elif k is S.Zero:
                return S.One
            else:
                if k.is_positive:
                    if x is S.Infinity:
                        return S.Infinity
                    elif x is S.NegativeInfinity:
                        if k.is_odd:
                            return S.NegativeInfinity
                        else:
                            return S.Infinity
                    else:
                        return reduce(lambda r, i: r*(x - i), xrange(0, int(k)), 1)
                else:
                    if x is S.Infinity:
                        return S.Infinity
                    elif x is S.NegativeInfinity:
                        return S.Infinity
                    else:
                        return 1/reduce(lambda r, i: r*(x + i), xrange(1, abs(int(k)) + 1), 1)
Ejemplo n.º 2
0
def dim_simplify(expr):
    """
    Simplify expression by recursively evaluating the dimension arguments.

    This function proceeds to a very rough dimensional analysis. It tries to
    simplify expression with dimensions, and it deletes all what multiplies a
    dimension without being a dimension. This is necessary to avoid strange
    behavior when Add(L, L) be transformed into Mul(2, L).
    """

    args = []
    for arg in expr.args:
        if isinstance(arg, (Mul, Pow, Add)):
            arg = dim_simplify(arg)
        args.append(arg)

    if isinstance(expr, Pow):
        return args[0].pow(args[1])
    elif isinstance(expr, Add):
        args = [arg for arg in args if isinstance(arg, Dimension)]
        return reduce(lambda x, y: x.add(y), args)
    elif isinstance(expr, Mul):
        args = [arg for arg in args if isinstance(arg, Dimension)]
        return reduce(lambda x, y: x.mul(y), args)
    else:
        return expr
Ejemplo n.º 3
0
        def _rebuild(expr):
            generator = mapping.get(expr)

            if generator is not None:
                return generator
            elif expr.is_Add:
                return reduce(add, list(map(_rebuild, expr.args)))
            elif expr.is_Mul:
                return reduce(mul, list(map(_rebuild, expr.args)))
            elif expr.is_Pow or isinstance(expr, (ExpBase, Exp1)):
                b, e = expr.as_base_exp()
                # look for bg**eg whose integer power may be b**e
                for gen, (bg, eg) in powers:
                    if bg == b and Mod(e, eg) == 0:
                        return mapping.get(gen)**int(e/eg)
                if e.is_Integer and e is not S.One:
                    return _rebuild(b)**int(e)

            try:
                return domain.convert(expr)
            except CoercionFailed:
                if not domain.is_Field and domain.has_assoc_Field:
                    return domain.get_field().convert(expr)
                else:
                    raise
Ejemplo n.º 4
0
def dynamicsymbols(names, level=0):
    """Uses symbols and Function for functions of time.

    Creates a SymPy UndefinedFunction, which is then initialized as a function
    of a variable, the default being Symbol('t').

    Parameters
    ==========

    names : str
        Names of the dynamic symbols you want to create; works the same way as
        inputs to symbols
    level : int
        Level of differentiation of the returned function; d/dt once of t,
        twice of t, etc.

    Examples
    ========

    >>> from sympy.physics.vector import dynamicsymbols
    >>> from sympy import diff, Symbol
    >>> q1 = dynamicsymbols('q1')
    >>> q1
    q1(t)
    >>> diff(q1, Symbol('t'))
    Derivative(q1(t), t)

    """
    esses = symbols(names, cls=Function)
    t = dynamicsymbols._t
    if iterable(esses):
        esses = [reduce(diff, [t] * level, e(t)) for e in esses]
        return esses
    else:
        return reduce(diff, [t] * level, esses(t))
Ejemplo n.º 5
0
    def qsimplify(cls, expr):
        """
        Simplify expression by recursively evaluating the quantity arguments.

        If units are encountered, as it can be when using Constant, they are
        converted to quantity.
        """

        def redmul(x, y):
            """
            Function used to combine args in multiplications.

            This is necessary because the previous computation was not commutative,
            and Mul(3, u) was not simplified; but Mul(u, 3) was.
            """
            if isinstance(x, Quantity):
                return x.mul(y)
            elif isinstance(y, Quantity):
                return y.mul(x)
            else:
                return x*y

        args = []
        for arg in expr.args:
            arg = arg.evalf()
            if isinstance(arg, (Mul, Pow, Add)):
                arg = cls.qsimplify(arg)
            args.append(arg)

        q_args, o_args = [], []

        for arg in args:
            if isinstance(arg, Quantity):
                q_args.append(arg)
            elif isinstance(arg, Unit):
                # replace unit by a quantity to make the simplification
                q_args.append(arg.as_quantity)
            else:
                o_args.append(arg)
            

        if isinstance(expr, Pow):
            return args[0].pow(args[1])
        elif isinstance(expr, Add):
            if q_args != []:
                quantities = reduce(lambda x, y: x.add(y), q_args)
            else:
                quantities = []
            return reduce(lambda x, y: x+y, o_args, quantities)
        elif isinstance(expr, Mul):
            if q_args != []:
                quantities = reduce(lambda x, y: x.mul(y), q_args)
            else:
                quantities = []
            return reduce(redmul, o_args, quantities)
        else:
            return expr
Ejemplo n.º 6
0
    def eval(cls, x, k):
        x = sympify(x)
        k = sympify(k)

        if x is S.NaN or k is S.NaN:
            return S.NaN
        elif x is S.One:
            return factorial(k)
        elif k.is_Integer:
            if k is S.Zero:
                return S.One
            else:
                if k.is_positive:
                    if x is S.Infinity:
                        return S.Infinity
                    elif x is S.NegativeInfinity:
                        if k.is_odd:
                            return S.NegativeInfinity
                        else:
                            return S.Infinity
                    else:
                        if isinstance(x, Poly):
                            gens = x.gens
                            if len(gens)!= 1:
                                raise ValueError("rf only defined for "
                                            "polynomials on one generator")
                            else:
                                return reduce(lambda r, i:
                                              r*(x.shift(i).expand()),
                                              range(0, int(k)), 1)
                        else:
                            return reduce(lambda r, i: r*(x + i),
                                        range(0, int(k)), 1)

                else:
                    if x is S.Infinity:
                        return S.Infinity
                    elif x is S.NegativeInfinity:
                        return S.Infinity
                    else:
                        if isinstance(x, Poly):
                            gens = x.gens
                            if len(gens)!= 1:
                                raise ValueError("rf only defined for "
                                            "polynomials on one generator")
                            else:
                                return 1/reduce(lambda r, i:
                                                r*(x.shift(-i).expand()),
                                                range(1, abs(int(k)) + 1), 1)
                        else:
                            return 1/reduce(lambda r, i:
                                            r*(x - i),
                                            range(1, abs(int(k)) + 1), 1)
Ejemplo n.º 7
0
def merge_explicit(matadd):
    """ Merge explicit MatrixBase arguments

    Examples
    ========

    >>> from sympy import MatrixSymbol, eye, Matrix, MatAdd, pprint
    >>> from sympy.matrices.expressions.matadd import merge_explicit
    >>> A = MatrixSymbol('A', 2, 2)
    >>> B = eye(2)
    >>> C = Matrix([[1, 2], [3, 4]])
    >>> X = MatAdd(A, B, C)
    >>> pprint(X)
        [1  0]   [1  2]
    A + [    ] + [    ]
        [0  1]   [3  4]
    >>> pprint(merge_explicit(X))
        [2  2]
    A + [    ]
        [3  5]
    """
    groups = sift(matadd.args, lambda arg: isinstance(arg, MatrixBase))
    if len(groups[True]) > 1:
        return MatAdd(*(groups[False] + [reduce(add, groups[True])]))
    else:
        return matadd
Ejemplo n.º 8
0
def _get_indices_Mul(expr, return_dummies=False):
    """Determine the outer indices of a Mul object.

    >>> from sympy.tensor.index_methods import _get_indices_Mul
    >>> from sympy.tensor.indexed import IndexedBase, Idx
    >>> i, j, k = map(Idx, ['i', 'j', 'k'])
    >>> x = IndexedBase('x')
    >>> y = IndexedBase('y')
    >>> _get_indices_Mul(x[i, k]*y[j, k])
    (set([i, j]), {})
    >>> _get_indices_Mul(x[i, k]*y[j, k], return_dummies=True)
    (set([i, j]), {}, (k,))

    """

    inds = list(map(get_indices, expr.args))
    inds, syms = list(zip(*inds))

    inds = list(map(list, inds))
    inds = list(reduce(lambda x, y: x + y, inds))
    inds, dummies = _remove_repeated(inds)

    symmetry = {}
    for s in syms:
        for pair in s:
            if pair in symmetry:
                symmetry[pair] *= s[pair]
            else:
                symmetry[pair] = s[pair]

    if return_dummies:
        return inds, symmetry, dummies
    else:
        return inds, symmetry
Ejemplo n.º 9
0
def dim_simplify(expr):
    """
    NOTE: this function could be deprecated in the future.

    Simplify expression by recursively evaluating the dimension arguments.

    This function proceeds to a very rough dimensional analysis. It tries to
    simplify expression with dimensions, and it deletes all what multiplies a
    dimension without being a dimension. This is necessary to avoid strange
    behavior when Add(L, L) be transformed into Mul(2, L).
    """

    if isinstance(expr, Dimension):
        return expr

    if isinstance(expr, Pow):
        return dim_simplify(expr.base)**dim_simplify(expr.exp)
    elif isinstance(expr, Function):
        return dim_simplify(expr.args[0])
    elif isinstance(expr, Add):
        if (all(isinstance(arg, Dimension) for arg in expr.args) or
            all(arg.is_dimensionless for arg in expr.args if isinstance(arg, Dimension))):
            return reduce(lambda x, y: x.add(y), expr.args)
        else:
            raise ValueError("Dimensions cannot be added: %s" % expr)
    elif isinstance(expr, Mul):
        return Dimension(Mul(*[dim_simplify(i).name for i in expr.args if isinstance(i, Dimension)]))

    raise ValueError("Cannot be simplifed: %s", expr)
Ejemplo n.º 10
0
def prde_normal_denom(fa, fd, G, DE):
    """
    Parametric Risch Differential Equation - Normal part of the denominator.

    Given a derivation D on k[t] and f, g1, ..., gm in k(t) with f weakly
    normalized with respect to t, return the tuple (a, b, G, h) such that
    a, h in k[t], b in k<t>, G = [g1, ..., gm] in k(t)^m, and for any solution
    c1, ..., cm in Const(k) and y in k(t) of Dy + f*y == Sum(ci*gi, (i, 1, m)),
    q == y*h in k<t> satisfies a*Dq + b*q == Sum(ci*Gi, (i, 1, m)).
    """
    dn, ds = splitfactor(fd, DE)
    Gas, Gds = list(zip(*G))
    gd = reduce(lambda i, j: i.lcm(j), Gds, Poly(1, DE.t))
    en, es = splitfactor(gd, DE)

    p = dn.gcd(en)
    h = en.gcd(en.diff(DE.t)).quo(p.gcd(p.diff(DE.t)))

    a = dn*h
    c = a*h

    ba = a*fa - dn*derivation(h, DE)*fd
    ba, bd = ba.cancel(fd, include=True)

    G = [(c*A).cancel(D, include=True) for A, D in G]

    return (a, (ba, bd), G, h)
Ejemplo n.º 11
0
 def pull_out_u_rl(integrand):
     if any([integrand.has(f) for f in functions]):
         args = [arg for arg in integrand.args if any(isinstance(arg, cls) for cls in functions)]
         if args:
             u = reduce(lambda a, b: a * b, args)
             dv = integrand / u
             return u, dv
Ejemplo n.º 12
0
    def _eval_matrix_mul(self, other):
        from sympy import Add
        # cache attributes for faster access
        self_rows, self_cols = self.rows, self.cols
        other_rows, other_cols = other.rows, other.cols
        other_len = other_rows * other_cols
        new_mat_rows = self.rows
        new_mat_cols = other.cols

        # preallocate the array
        new_mat = [S.Zero]*new_mat_rows*new_mat_cols

        # if we multiply an n x 0 with a 0 x m, the
        # expected behavior is to produce an n x m matrix of zeros
        if self.cols != 0 and other.rows != 0:
            # cache self._mat and other._mat for performance
            mat = self._mat
            other_mat = other._mat
            for i in range(len(new_mat)):
                row, col = i // new_mat_cols, i % new_mat_cols
                row_indices = range(self_cols*row, self_cols*(row+1))
                col_indices = range(col, other_len, other_cols)
                vec = (mat[a]*other_mat[b] for a,b in zip(row_indices, col_indices))
                try:
                    new_mat[i] = Add(*vec)
                except (TypeError, SympifyError):
                    # Block matrices don't work with `sum` or `Add` (ISSUE #11599)
                    # They don't work with `sum` because `sum` tries to add `0`
                    # initially, and for a matrix, that is a mix of a scalar and
                    # a matrix, which raises a TypeError. Fall back to a
                    # block-matrix-safe way to multiply if the `sum` fails.
                    vec = (mat[a]*other_mat[b] for a,b in zip(row_indices, col_indices))
                    new_mat[i] = reduce(lambda a,b: a + b, vec)
        return classof(self, other)._new(new_mat_rows, new_mat_cols, new_mat, copy=False)
Ejemplo n.º 13
0
def prde_linear_constraints(a, b, G, DE):
    """
    Parametric Risch Differential Equation - Generate linear constraints on the constants.

    Given a derivation D on k[t], a, b, in k[t] with gcd(a, b) == 1, and
    G = [g1, ..., gm] in k(t)^m, return Q = [q1, ..., qm] in k[t]^m and a
    matrix M with entries in k(t) such that for any solution c1, ..., cm in
    Const(k) and p in k[t] of a*Dp + b*p == Sum(ci*gi, (i, 1, m)),
    (c1, ..., cm) is a solution of Mx == 0, and p and the ci satisfy
    a*Dp + b*p == Sum(ci*qi, (i, 1, m)).

    Because M has entries in k(t), and because Matrix doesn't play well with
    Poly, M will be a Matrix of Basic expressions.
    """
    m = len(G)

    Gns, Gds = list(zip(*G))
    d = reduce(lambda i, j: i.lcm(j), Gds)
    d = Poly(d, field=True)
    Q = [(ga*(d).quo(gd)).div(d) for ga, gd in G]

    if not all([ri.is_zero for _, ri in Q]):
        N = max([ri.degree(DE.t) for _, ri in Q])
        M = Matrix(N + 1, m, lambda i, j: Q[j][1].nth(i))
    else:
        M = Matrix()  # No constraints, return the empty matrix.

    qs, _ = list(zip(*Q))
    return (qs, M)
Ejemplo n.º 14
0
 def _module_quotient(self, other, relations=False):
     # See: [SCA, section 2.8.4]
     if relations and len(other.gens) != 1:
         raise NotImplementedError
     if len(other.gens) == 0:
         return self.ring.ideal(1)
     elif len(other.gens) == 1:
         # We do some trickery. Let f be the (vector!) generating ``other``
         # and f1, .., fn be the (vectors) generating self.
         # Consider the submodule of R^{r+1} generated by (f, 1) and
         # {(fi, 0) | i}. Then the intersection with the last module
         # component yields the quotient.
         g1 = list(other.gens[0]) + [1]
         gi = [list(x) + [0] for x in self.gens]
         # NOTE: We *need* to use an elimination order
         M = self.ring.free_module(self.rank + 1).submodule(*([g1] + gi),
                                         order='ilex', TOP=False)
         if not relations:
             return self.ring.ideal(*[x[-1] for x in M._groebner_vec() if
                                      all(y == self.ring.zero for y in x[:-1])])
         else:
             G, R = M._groebner_vec(extended=True)
             indices = [i for i, x in enumerate(G) if
                        all(y == self.ring.zero for y in x[:-1])]
             return (self.ring.ideal(*[G[i][-1] for i in indices]),
                     [[-x for x in R[i][1:]] for i in indices])
     # For more generators, we use I : <h1, .., hn> = intersection of
     #                                    {I : <hi> | i}
     # TODO this can be done more efficiently
     return reduce(lambda x, y: x.intersect(y),
         (self._module_quotient(self.container.submodule(x)) for x in other.gens))
Ejemplo n.º 15
0
def test_treeapply():
    tree = ([3, 3], [4, 1], 2)
    assert treeapply(tree, {list: min, tuple: max}) == 3

    add = lambda *args: sum(args)
    mul = lambda *args: reduce(lambda a, b: a*b, args, 1)
    assert treeapply(tree, {list: add, tuple: mul}) == 60
Ejemplo n.º 16
0
 def get_total_scale_factor(expr):
     if isinstance(expr, Mul):
         return reduce(lambda x, y: x * y, [get_total_scale_factor(i) for i in expr.args])
     elif isinstance(expr, Pow):
         return get_total_scale_factor(expr.base) ** expr.exp
     elif isinstance(expr, Quantity):
         return expr.scale_factor
     return expr
Ejemplo n.º 17
0
Archivo: pde.py Proyecto: AALEKH/sympy
def _separate(eq, dep, others):
    """Separate expression into two parts based on dependencies of variables."""

    # FIRST PASS
    # Extract derivatives depending our separable variable...
    terms = set()
    for term in eq.args:
        if term.is_Mul:
            for i in term.args:
                if i.is_Derivative and not i.has(*others):
                    terms.add(term)
                    continue
        elif term.is_Derivative and not term.has(*others):
            terms.add(term)
    # Find the factor that we need to divide by
    div = set()
    for term in terms:
        ext, sep = term.expand().as_independent(dep)
        # Failed?
        if sep.has(*others):
            return None
        div.add(ext)
    # FIXME: Find lcm() of all the divisors and divide with it, instead of
    # current hack :(
    # http://code.google.com/p/sympy/issues/detail?id=1498
    if len(div) > 0:
        final = 0
        for term in eq.args:
            eqn = 0
            for i in div:
                eqn += term / i
            final += simplify(eqn)
        eq = final

    # SECOND PASS - separate the derivatives
    div = set()
    lhs = rhs = 0
    for term in eq.args:
        # Check, whether we have already term with independent variable...
        if not term.has(*others):
            lhs += term
            continue
        # ...otherwise, try to separate
        temp, sep = term.expand().as_independent(dep)
        # Failed?
        if sep.has(*others):
            return None
        # Extract the divisors
        div.add(sep)
        rhs -= term.expand()
    # Do the division
    fulldiv = reduce(operator.add, div)
    lhs = simplify(lhs/fulldiv).expand()
    rhs = simplify(rhs/fulldiv).expand()
    # ...and check whether we were successful :)
    if lhs.has(*others) or rhs.has(dep):
        return None
    return [lhs, rhs]
Ejemplo n.º 18
0
def limited_integrate_reduce(fa, fd, G, DE):
    """
    Simpler version of step 1 & 2 for the limited integration problem.

    Given a derivation D on k(t) and f, g1, ..., gn in k(t), return
    (a, b, h, N, g, V) such that a, b, h in k[t], N is a non-negative integer,
    g in k(t), V == [v1, ..., vm] in k(t)^m, and for any solution v in k(t),
    c1, ..., cm in C of f == Dv + Sum(ci*wi, (i, 1, m)), p = v*h is in k<t>, and
    p and the ci satisfy a*Dp + b*p == g + Sum(ci*vi, (i, 1, m)).  Furthermore,
    if S1irr == Sirr, then p is in k[t], and if t is nonlinear or Liouvillian
    over k, then deg(p) <= N.

    So that the special part is always computed, this function calls the more
    general prde_special_denom() automatically if it cannot determine that
    S1irr == Sirr.  Furthermore, it will automatically call bound_degree() when
    t is linear and non-Liouvillian, which for the transcendental case, implies
    that Dt == a*t + b with for some a, b in k*.
    """
    dn, ds = splitfactor(fd, DE)
    E = [splitfactor(gd, DE) for _, gd in G]
    En, Es = list(zip(*E))
    c = reduce(lambda i, j: i.lcm(j), (dn,) + En)  # lcm(dn, en1, ..., enm)
    hn = c.gcd(c.diff(DE.t))
    a = hn
    b = -derivation(hn, DE)
    N = 0

    # These are the cases where we know that S1irr = Sirr, but there could be
    # others, and this algorithm will need to be extended to handle them.
    if DE.case in ['base', 'primitive', 'exp', 'tan']:
        hs = reduce(lambda i, j: i.lcm(j), (ds,) + Es)  # lcm(ds, es1, ..., esm)
        a = hn*hs
        b = -derivation(hn, DE) - (hn*derivation(hs, DE)).quo(hs)
        mu = min(order_at_oo(fa, fd, DE.t), min([order_at_oo(ga, gd, DE.t) for
            ga, gd in G]))
        # So far, all the above are also nonlinear or Liouvillian, but if this
        # changes, then this will need to be updated to call bound_degree()
        # as per the docstring of this function (DE.case == 'other_linear').
        N = hn.degree(DE.t) + hs.degree(DE.t) + max(0, 1 - DE.d.degree(DE.t) - mu)
    else:
        # TODO: implement this
        raise NotImplementedError

    V = [(-a*hn*ga).cancel(gd, include=True) for ga, gd in G]
    return (a, b, a, N, (a*hn*fa).cancel(fd, include=True), V)
Ejemplo n.º 19
0
def test_PolyRing_mul():
    R, x = ring("x", ZZ)
    F = [ x**2 + 2*i + 3 for i in range(4) ]

    assert R.mul(F) == reduce(mul, F) == x**8 + 24*x**6 + 206*x**4 + 744*x**2 + 945

    R, = ring("", ZZ)

    assert R.mul([2, 3, 5]) == 30
Ejemplo n.º 20
0
 def compute(l):
     # first check that no two differ by an integer
     for i, b in enumerate(l):
         if not b.is_Rational:
             return oo
         for j in range(i + 1, len(l)):
             if not Mod((b - l[j]).simplify(), 1):
                 return oo
     return reduce(ilcm, (x.q for x in l), 1)
Ejemplo n.º 21
0
def test_PolyRing_add():
    R, x = ring("x", ZZ)
    F = [ x**2 + 2*i + 3 for i in range(4) ]

    assert R.add(F) == reduce(add, F) == 4*x**2 + 24

    R, = ring("", ZZ)

    assert R.add([2, 5, 7]) == 14
Ejemplo n.º 22
0
    def perp_to_subspace(vec, basis):
        """projects vec onto the subspace given
        by the orthogonal basis ``basis``"""

        components = [project(vec, b) for b in basis]

        if len(basis) == 0:
            return vec

        return vec - reduce(lambda a, b: a + b, components)
Ejemplo n.º 23
0
        def _rebuild(expr):
            generator = mapping.get(expr)

            if generator is not None:
                return generator
            elif expr.is_Add:
                return reduce(add, list(map(_rebuild, expr.args)))
            elif expr.is_Mul:
                return reduce(mul, list(map(_rebuild, expr.args)))
            elif expr.is_Pow and expr.exp.is_Integer:
                return _rebuild(expr.base)**int(expr.exp)
            else:
                try:
                    return domain.convert(expr)
                except CoercionFailed:
                    if not domain.has_Field and domain.has_assoc_Field:
                        return domain.get_field().convert(expr)
                    else:
                        raise
Ejemplo n.º 24
0
 def pull_out_u_rl(integrand):
     if any([integrand.has(f) for f in functions]):
         args = [
             arg for arg in integrand.args if any(
                 isinstance(arg, cls) for cls in functions)
         ]
         if args:
             u = reduce(lambda a, b: a * b, args)
             dv = integrand / u
             return u, dv
def str_combinations(base, lst, rank=1, mode='_'):
    """
    Construct a list of strings of the form 'base+mode+indexes' where the
    indexes are formed by converting 'lst' to a list of strings and then
    forming the 'indexes' by concatenating combinations of elements from
    'lst' taken 'rank' at a time.
    """
    str_lst = list(map(lambda x: base + mode + x, map(lambda x: reduce(operator.add, x),
                        combinations(map(lambda x: str(x), lst), rank))))
    return str_lst
Ejemplo n.º 26
0
    def list_can_dims(self):
        """
        List all canonical dimension names.
        """

        if self._list_can_dims is None:
            gen = reduce(lambda x, y: x.mul(y), self._base_dims)
            self._list_can_dims = tuple(sorted(map(str, gen.keys())))

        return self._list_can_dims
Ejemplo n.º 27
0
        def _rebuild(expr):
            generator = mapping.get(expr)

            if generator is not None:
                return generator
            elif expr.is_Add:
                return reduce(add, list(map(_rebuild, expr.args)))
            elif expr.is_Mul:
                return reduce(mul, list(map(_rebuild, expr.args)))
            elif expr.is_Pow and expr.exp.is_Integer:
                return _rebuild(expr.base)**int(expr.exp)
            else:
                try:
                    return domain.convert(expr)
                except CoercionFailed:
                    if not domain.has_Field and domain.has_assoc_Field:
                        return domain.get_field().convert(expr)
                    else:
                        raise
Ejemplo n.º 28
0
    def list_can_dims(self):
        """
        List all canonical dimension names.
        """

        if self._list_can_dims is None:
            gen = reduce(lambda x, y: x.mul(y), self._base_dims)
            self._list_can_dims = tuple(sorted(map(str, gen.keys())))

        return self._list_can_dims
Ejemplo n.º 29
0
def reduce_inequalities(inequalities, symbols=[]):
    """Reduce a system of inequalities with rational coefficients.

    Examples
    ========

    >>> from sympy import sympify as S, Symbol
    >>> from sympy.abc import x, y
    >>> from sympy.solvers.inequalities import reduce_inequalities

    >>> reduce_inequalities(S(0) <= x + 3, [])
    And(-3 <= x, x < oo)

    >>> reduce_inequalities(S(0) <= x + y*2 - 1, [x])
    -2*y + 1 <= x
    """
    if not iterable(inequalities):
        inequalities = [inequalities]

    # prefilter
    keep = []
    for i in inequalities:
        if isinstance(i, Relational):
            i = i.func(i.lhs.as_expr() - i.rhs.as_expr(), 0)
        elif i not in (True, False):
            i = Eq(i, 0)
        if i == True:
            continue
        elif i == False:
            return S.false
        if i.lhs.is_number:
            raise NotImplementedError(
                "could not determine truth value of %s" % i)
        keep.append(i)
    inequalities = keep
    del keep

    gens = reduce(set.union, [i.free_symbols for i in inequalities], set())

    if not iterable(symbols):
        symbols = [symbols]
    symbols = set(symbols) or gens

    # make vanilla symbol real
    recast = dict([(i, Dummy(i.name, real=True))
        for i in gens if i.is_real is None])
    inequalities = [i.xreplace(recast) for i in inequalities]
    symbols = set([i.xreplace(recast) for i in symbols])

    # solve system
    rv = _reduce_inequalities(inequalities, symbols)

    # restore original symbols and return
    return rv.xreplace(dict([(v, k) for k, v in recast.items()]))
Ejemplo n.º 30
0
def str_combinations(base, lst, rank=1, mode='_'):
    """
    Construct a list of strings of the form 'base+mode+indexes' where the
    indexes are formed by converting 'lst' to a list of strings and then
    forming the 'indexes' by concatenating combinations of elements from
    'lst' taken 'rank' at a time.
    """
    a1 = combinations([str(x) for x in lst], rank)
    a2 = [reduce(operator.add, x) for x in a1]
    str_lst = [base + mode + x for x in a2]
    return str_lst
Ejemplo n.º 31
0
def str_combinations(base, lst, rank=1, mode='_'):
    """
    Construct a list of strings of the form 'base+mode+indexes' where the
    indexes are formed by converting 'lst' to a list of strings and then
    forming the 'indexes' by concatenating combinations of elements from
    'lst' taken 'rank' at a time.
    """
    a1 = combinations([str(x) for x in lst], rank)
    a2 = [reduce(operator.add, x) for x in a1]
    str_lst = [base + mode + x for x in a2]
    return str_lst
Ejemplo n.º 32
0
    def can_transf_matrix(self):
        """
        Return the canonical transformation matrix from the canonical to the
        base dimension basis.

        It is the inverse of the matrix computed with inv_can_transf_matrix().
        """

        #TODO: the inversion will fail if the system is inconsistent, for
        #      example if the matrix is not a square
        return reduce(lambda x, y: x.row_join(y),
                      [self.dim_can_vector(d) for d in self._base_dims]).inv()
Ejemplo n.º 33
0
def dim_simplify(expr):
    """
    Simplify expression by recursively evaluating the dimension arguments.

    This function proceeds to a very rough dimensional analysis. It tries to
    simplify expression with dimensions, and it deletes all what multiplies a
    dimension without being a dimension. This is necessary to avoid strange
    behavior when Add(L, L) be transformed into Mul(2, L).
    """

    args = []
    for arg in expr.args:
        if isinstance(arg, (Mul, Pow, Add)):
            arg = dim_simplify(arg)
        args.append(arg)

    if all([
            arg.is_number
            or (isinstance(arg, Dimension) and arg.is_dimensionless)
            for arg in args
    ]):
        return Dimension({})

    if isinstance(expr, Pow):
        if isinstance(args[0], Dimension):
            return args[0].pow(args[1])
        else:
            raise ValueError("Basis of Pow is not a Dimension: %s" % args[0])
    elif isinstance(expr, Add):
        if (all(isinstance(arg, Dimension) for arg in args)
                or all(arg.is_dimensionless()
                       for arg in args if isinstance(arg, Dimension))):
            return reduce(lambda x, y: x.add(y), args)
        else:
            raise ValueError("Dimensions cannot be added: %s" % expr)
    elif isinstance(expr, Mul):
        args = [arg for arg in args if isinstance(arg, Dimension)]
        return reduce(lambda x, y: x.mul(y), args)

    raise ValueError("Cannot be simplifed: %s", expr)
Ejemplo n.º 34
0
def dim_simplify(expr):
    """
    Simplify expression by recursively evaluating the dimension arguments.

    This function proceeds to a very rough dimensional analysis. It tries to
    simplify expression with dimensions, and it deletes all what multiplies a
    dimension without being a dimension. This is necessary to avoid strange
    behavior when Add(L, L) be transformed into Mul(2, L).
    """

    if isinstance(expr, Dimension):
        return expr

    if isinstance(expr, Symbol):
        return None

    args = []
    for arg in expr.args:
        if isinstance(arg, (Mul, Pow, Add, Symbol, Function)):
            arg = dim_simplify(arg)
        args.append(arg)

    if all([arg!=None and (arg.is_number or (isinstance(arg, Dimension) and arg.is_dimensionless)) for arg in args]):
        return Dimension({})

    if isinstance(expr, Function):
        raise ValueError("Arguments of this function cannot have a dimension: %s" % expr)
    elif isinstance(expr, Pow):
        if isinstance(args[0], Dimension):
            return args[0].pow(args[1])
        else:
            return None
    elif isinstance(expr, Add):
        dimargs = [arg for arg in args if isinstance(arg, Dimension)]
        if (all(isinstance(arg, Dimension) or arg==None for arg in args) or
            all(arg.is_dimensionless for arg in dimargs)):
            if len(dimargs)>0:
                return reduce(lambda x, y: x.add(y), dimargs)
            else:
                return Dimension({})
        else:
            raise ValueError("Dimensions cannot be added: %s" % expr)
    elif isinstance(expr, Mul):
        result = Dimension({})
        for arg in args:
            if isinstance(arg, Dimension):
                result = result.mul(arg)
            elif arg == None:
                return None
        return result

    return None
Ejemplo n.º 35
0
    def can_transf_matrix(self):
        """
        Return the canonical transformation matrix from the canonical to the
        base dimension basis.

        It is the inverse of the matrix computed with inv_can_transf_matrix().
        """

        #TODO: the inversion will fail if the system is inconsistent, for
        #      example if the matrix is not a square
        return reduce(lambda x, y: x.row_join(y),
                      [self.dim_can_vector(d) for d in self._base_dims]
                      ).inv()
Ejemplo n.º 36
0
 def _eval_derivative(self, s):
     # adapted from Mul._eval_derivative
     args = list(self.args)
     terms = []
     for i in range(len(args)):
         d = args[i].diff(s)
         if d:
             # Note: reduce is used in step of Mul as Mul is unable to
             # handle subtypes and operation priority:
             terms.append(
                 reduce(lambda x, y: x * y, (args[:i] + [d] + args[i + 1:]),
                        S.One))
     return VecAdd.fromiter(terms)
Ejemplo n.º 37
0
def str_combinations(base, lst, rank=1, mode='_'):
    """
    Construct a list of strings of the form 'base+mode+indexes' where the
    indexes are formed by converting 'lst' to a list of strings and then
    forming the 'indexes' by concatenating combinations of elements from
    'lst' taken 'rank' at a time.
    """
    str_lst = list(
        map(
            lambda x: base + mode + x,
            map(lambda x: reduce(operator.add, x),
                combinations(map(lambda x: str(x), lst), rank))))
    return str_lst
Ejemplo n.º 38
0
def dim_simplify(expr):
    """
    Simplify expression by recursively evaluating the dimension arguments.

    This function proceeds to a very rough dimensional analysis. It tries to
    simplify expression with dimensions, and it deletes all what multiplies a
    dimension without being a dimension. This is necessary to avoid strange
    behavior when Add(L, L) be transformed into Mul(2, L).
    """

    if isinstance(expr, Dimension):
        return expr

    args = []
    for arg in expr.args:
        if isinstance(arg, (Mul, Pow, Add)):
            arg = dim_simplify(arg)
        args.append(arg)

    if all([arg.is_number or (isinstance(arg, Dimension) and arg.is_dimensionless) for arg in args]):
        return Dimension({})

    if isinstance(expr, Pow):
        if isinstance(args[0], Dimension):
            return args[0].pow(args[1])
        else:
            raise ValueError("Basis of Pow is not a Dimension: %s" % args[0])
    elif isinstance(expr, Add):
        if (all(isinstance(arg, Dimension) for arg in args) or
            all(arg.is_dimensionless for arg in args if isinstance(arg, Dimension))):
            return reduce(lambda x, y: x.add(y), args)
        else:
            raise ValueError("Dimensions cannot be added: %s" % expr)
    elif isinstance(expr, Mul):
        args = [arg for arg in args if isinstance(arg, Dimension)]
        return reduce(lambda x, y: x.mul(y), args)

    raise ValueError("Cannot be simplifed: %s", expr)
Ejemplo n.º 39
0
Archivo: basic.py Proyecto: wxgeo/sympy
    def free_symbols(self):
        """Return from the atoms of self those which are free symbols.

        For most expressions, all symbols are free symbols. For some classes
        this is not true. e.g. Integrals use Symbols for the dummy variables
        which are bound variables, so Integral has a method to return all symbols
        except those. Derivative keeps track of symbols with respect to which it
        will perform a derivative; those are bound variables, too, so it has
        its own symbols method.

        Any other method that uses bound variables should implement a symbols
        method."""
        union = set.union
        return reduce(union, [arg.free_symbols for arg in self.args], set())
Ejemplo n.º 40
0
    def _find_dynamicsymbols(self, inlist, insyms=[]):
        """Finds all non-supplied dynamicsymbols in the expressions."""
        from sympy.core.function import AppliedUndef, Derivative
        t = dynamicsymbols._t
        return reduce(set.union, [set([i]) for j in inlist
            for i in j.atoms(AppliedUndef, Derivative)
            if i.atoms() == set([t])], set()) - insyms

        temp_f = set().union(*[i.atoms(AppliedUndef) for i in inlist])
        temp_d = set().union(*[i.atoms(Derivative) for i in inlist])
        set_f = set([a for a in temp_f if a.args == (t,)])
        set_d = set([a for a in temp_d if ((a.args[0] in set_f) and all([i == t
                     for i in a.variables]))])
        return list(set.union(set_f, set_d) - set(insyms))
Ejemplo n.º 41
0
    def free_symbols(self):
        """Return from the atoms of self those which are free symbols.

        For most expressions, all symbols are free symbols. For some classes
        this is not true. e.g. Integrals use Symbols for the dummy variables
        which are bound variables, so Integral has a method to return all symbols
        except those. Derivative keeps track of symbols with respect to which it
        will perform a derivative; those are bound variables, too, so it has
        its own symbols method.

        Any other method that uses bound variables should implement a symbols
        method."""
        union = set.union
        return reduce(union, [arg.free_symbols for arg in self.args], set())
Ejemplo n.º 42
0
def weak_normalizer(a, d, DE, z=None):
    """
    Weak normalization.

    Explanation
    ===========

    Given a derivation D on k[t] and f == a/d in k(t), return q in k[t]
    such that f - Dq/q is weakly normalized with respect to t.

    f in k(t) is said to be "weakly normalized" with respect to t if
    residue_p(f) is not a positive integer for any normal irreducible p
    in k[t] such that f is in R_p (Definition 6.1.1).  If f has an
    elementary integral, this is equivalent to no logarithm of
    integral(f) whose argument depends on t has a positive integer
    coefficient, where the arguments of the logarithms not in k(t) are
    in k[t].

    Returns (q, f - Dq/q)
    """
    z = z or Dummy('z')
    dn, ds = splitfactor(d, DE)

    # Compute d1, where dn == d1*d2**2*...*dn**n is a square-free
    # factorization of d.
    g = gcd(dn, dn.diff(DE.t))
    d_sqf_part = dn.quo(g)
    d1 = d_sqf_part.quo(gcd(d_sqf_part, g))

    a1, b = gcdex_diophantine(
        d.quo(d1).as_poly(DE.t), d1.as_poly(DE.t), a.as_poly(DE.t))
    r = (a - Poly(z, DE.t) * derivation(d1, DE)).as_poly(DE.t).resultant(
        d1.as_poly(DE.t))
    r = Poly(r, z)

    if not r.expr.has(z):
        return (Poly(1, DE.t), (a, d))

    N = [i for i in r.real_roots() if i in ZZ and i > 0]

    q = reduce(mul,
               [gcd(a - Poly(n, DE.t) * derivation(d1, DE), d1) for n in N],
               Poly(1, DE.t))

    dq = derivation(q, DE)
    sn = q * a - d * dq
    sd = q * d
    sn, sd = sn.cancel(sd, include=True)

    return (q, (sn, sd))
Ejemplo n.º 43
0
    def eval(cls, x, k):
        x = sympify(x)
        k = sympify(k)

        if x is S.NaN or k is S.NaN:
            return S.NaN
        elif k.is_integer and x == k:
            return factorial(x)
        elif k.is_Integer:
            if k is S.Zero:
                return S.One
            else:
                if k.is_positive:
                    if x is S.Infinity:
                        return S.Infinity
                    elif x is S.NegativeInfinity:
                        if k.is_odd:
                            return S.NegativeInfinity
                        else:
                            return S.Infinity
                    else:
                        try:
                            F, opt = poly_from_expr(x)
                        except PolificationFailed:
                            return reduce(lambda r, i: r * (x - i),
                                          range(0, int(k)), 1)
                        if len(opt.gens) > 1 or F.degree() <= 1:
                            return reduce(lambda r, i: r * (x - i),
                                          range(0, int(k)), 1)
                        else:
                            v = opt.gens[0]
                            return reduce(
                                lambda r, i: r * (F.subs(v, v - i).expand()),
                                range(0, int(k)), 1)
                else:
                    if x is S.Infinity:
                        return S.Infinity
                    elif x is S.NegativeInfinity:
                        return S.Infinity
                    else:
                        try:
                            F, opt = poly_from_expr(x)
                        except PolificationFailed:
                            return 1 / reduce(lambda r, i: r * (x + i),
                                              range(1,
                                                    abs(int(k)) + 1), 1)
                        if len(opt.gens) > 1 or F.degree() <= 1:
                            return 1 / reduce(lambda r, i: r * (x + i),
                                              range(1,
                                                    abs(int(k)) + 1), 1)
                        else:
                            v = opt.gens[0]
                            return 1 / reduce(
                                lambda r, i: r * (F.subs(v, v + i).expand()),
                                range(1,
                                      abs(int(k)) + 1), 1)
Ejemplo n.º 44
0
def dynamicsymbols(names, level=0):
    """Uses symbols and Function for functions of time.

    Creates a SymPy UndefinedFunction, which is then initialized as a function
    of a variable, the default being Symbol('t').

    Parameters
    ==========

    names : str
        Names of the dynamic symbols you want to create; works the same way as
        inputs to symbols
    level : int
        Level of differentiation of the returned function; d/dt once of t,
        twice of t, etc.

    Examples
    ========

    >>> from sympy.physics.vector import dynamicsymbols
    >>> from sympy import diff, Symbol
    >>> q1 = dynamicsymbols('q1')
    >>> q1
    q1(t)
    >>> diff(q1, Symbol('t'))
    Derivative(q1(t), t)

    """

    esses = symbols(names, cls=Function)
    t = dynamicsymbols._t
    if hasattr(esses, '__iter__'):
        esses = [reduce(diff, [t] * level, e(t)) for e in esses]
        return esses
    else:
        return reduce(diff, [t] * level, esses(t))
Ejemplo n.º 45
0
    def can_transf_matrix(self):
        """
        Useless method, kept for compatibility with previous versions.

        DO NOT USE.

        Return the canonical transformation matrix from the canonical to the
        base dimension basis.

        It is the inverse of the matrix computed with inv_can_transf_matrix().
        """

        #TODO: the inversion will fail if the system is inconsistent, for
        #      example if the matrix is not a square
        return reduce(lambda x, y: x.row_join(y),
                      [self.dim_can_vector(d) for d in sorted(self.base_dims, key=str)]
                      ).inv()
Ejemplo n.º 46
0
def root_factors(f, *gens, **args):
    """
    Returns all factors of a univariate polynomial.

    Examples
    ========

    >>> from sympy.abc import x, y
    >>> from sympy.polys.polyroots import root_factors

    >>> root_factors(x**2 - y, x)
    [x - sqrt(y), x + sqrt(y)]

    """
    args = dict(args)
    filter = args.pop('filter', None)

    F = Poly(f, *gens, **args)

    if not F.is_Poly:
        return [f]

    if F.is_multivariate:
        raise ValueError('multivariate polynomials are not supported')

    x = F.gens[0]

    zeros = roots(F, filter=filter)

    if not zeros:
        factors = [F]
    else:
        factors, N = [], 0

        for r, n in ordered(zeros.items()):
            factors, N = factors + [Poly(x - r, x)]*n, N + n

        if N < F.degree():
            G = reduce(lambda p, q: p*q, factors)
            factors.append(F.quo(G))

    if not isinstance(f, Poly):
        factors = [ f.as_expr() for f in factors ]

    return factors
def _get_indices_Add(expr):
    """Determine outer indices of an Add object.

    In a sum, each term must have the same set of outer indices.  A valid
    expression could be

        x(i)*y(j) - x(j)*y(i)

    But we do not allow expressions like:

        x(i)*y(j) - z(j)*z(j)

    FIXME: Add support for Numpy broadcasting

    Examples
    ========

    >>> from sympy.tensor.index_methods import _get_indices_Add
    >>> from sympy.tensor.indexed import IndexedBase, Idx
    >>> i, j, k = map(Idx, ['i', 'j', 'k'])
    >>> x = IndexedBase('x')
    >>> y = IndexedBase('y')
    >>> _get_indices_Add(x[i] + x[k]*y[i, k])
    ({i}, {})

    """

    inds = list(map(get_indices, expr.args))
    inds, syms = list(zip(*inds))

    # allow broadcast of scalars
    non_scalars = [x for x in inds if x != set()]
    if not non_scalars:
        return set(), {}

    if not all([x == non_scalars[0] for x in non_scalars[1:]]):
        raise IndexConformanceException("Indices are not consistent: %s" %
                                        expr)
    if not reduce(lambda x, y: x != y or y, syms):
        symmetries = syms[0]
    else:
        # FIXME: search for symmetries
        symmetries = {}

    return non_scalars[0], symmetries
Ejemplo n.º 48
0
def And(*args):
    """Defines the three valued ``And`` behaviour for a 2-tuple of
     three valued logic values"""
    def reduce_and(cmp_intervala, cmp_intervalb):
        if cmp_intervala[0] is False or cmp_intervalb[0] is False:
            first = False
        elif cmp_intervala[0] is None or cmp_intervalb[0] is None:
            first = None
        else:
            first = True
        if cmp_intervala[1] is False or cmp_intervalb[1] is False:
            second = False
        elif cmp_intervala[1] is None or cmp_intervalb[1] is None:
            second = None
        else:
            second = True
        return (first, second)
    return reduce(reduce_and, args)
Ejemplo n.º 49
0
    def inv_can_transf_matrix(self):
        """
        Compute the inverse transformation matrix from the base to the
        canonical dimension basis.

        It corresponds to the matrix where columns are the vector of base
        dimensions in canonical basis.

        This matrix will almost never be used because dimensions are always
        define with respect to the canonical basis, so no work has to be done
        to get them in this basis. Nonetheless if this matrix is not square
        (or not invertible) it means that we have chosen a bad basis.
        """

        matrix = reduce(lambda x, y: x.row_join(y),
                        [self.dim_can_vector(d) for d in self._base_dims])

        return matrix
Ejemplo n.º 50
0
 def _module_quotient(self, other, relations=False):
     # See: [SCA, section 2.8.4]
     if relations and len(other.gens) != 1:
         raise NotImplementedError
     if len(other.gens) == 0:
         return self.ring.ideal(1)
     elif len(other.gens) == 1:
         # We do some trickery. Let f be the (vector!) generating ``other``
         # and f1, .., fn be the (vectors) generating self.
         # Consider the submodule of R^{r+1} generated by (f, 1) and
         # {(fi, 0) | i}. Then the intersection with the last module
         # component yields the quotient.
         g1 = list(other.gens[0]) + [1]
         gi = [list(x) + [0] for x in self.gens]
         # NOTE: We *need* to use an elimination order
         M = self.ring.free_module(self.rank + 1).submodule(
             *([g1] + gi), order="ilex", TOP=False
         )
         if not relations:
             return self.ring.ideal(
                 *[
                     x[-1]
                     for x in M._groebner_vec()
                     if all(y == self.ring.zero for y in x[:-1])
                 ]
             )
         else:
             G, R = M._groebner_vec(extended=True)
             indices = [
                 i
                 for i, x in enumerate(G)
                 if all(y == self.ring.zero for y in x[:-1])
             ]
             return (
                 self.ring.ideal(*[G[i][-1] for i in indices]),
                 [[-x for x in R[i][1:]] for i in indices],
             )
     # For more generators, we use I : <h1, .., hn> = intersection of
     #                                    {I : <hi> | i}
     # TODO this can be done more efficiently
     return reduce(
         lambda x, y: x.intersect(y),
         (self._module_quotient(self.container.submodule(x)) for x in other.gens),
     )
Ejemplo n.º 51
0
    def _eval_matrix_mul(self, other):
        from sympy import Add
        # cache attributes for faster access
        self_rows, self_cols = self.rows, self.cols
        other_rows, other_cols = other.rows, other.cols
        other_len = other_rows * other_cols
        new_mat_rows = self_rows
        if other.rows == 1:
            new_mat_cols = other.rows
            other_rows, other_cols = other_cols, other_rows
        else:
            new_mat_cols = other.cols

        # preallocate the array
        new_mat = [self.zero] * new_mat_rows * new_mat_cols

        # if we multiply an n x 0 with a 0 x m, the
        # expected behavior is to produce an n x m matrix of zeros
        if self_cols != 0 and other_rows != 0:
            # cache self._args and other._args for performance
            mat = self._args
            other_mat = other._args
            for i in range(len(new_mat)):
                row, col = i // new_mat_cols, i % new_mat_cols
                row_indices = range(self_cols * row, self_cols * (row + 1))
                col_indices = range(col, other_len, other_cols)
                vec = (mat[a] * other_mat[b]
                       for a, b in zip(row_indices, col_indices))
                try:
                    new_mat[i] = Add(*vec)
                except (TypeError, SympifyError):
                    # Block matrices don't work with `sum` or `Add` (ISSUE #11599)
                    # They don't work with `sum` because `sum` tries to add `0`
                    # initially, and for a matrix, that is a mix of a scalar and
                    # a matrix, which raises a TypeError. Fall back to a
                    # block-matrix-safe way to multiply if the `sum` fails.
                    vec = (mat[a] * other_mat[b]
                           for a, b in zip(row_indices, col_indices))
                    new_mat[i] = reduce(lambda a, b: a + b, vec)
        return classof(self, other)._new(new_mat_rows,
                                         new_mat_cols,
                                         new_mat,
                                         copy=False)
Ejemplo n.º 52
0
def find_pure_symbol_int_repr(symbols, unknown_clauses):
    """
    Same as find_pure_symbol, but arguments are expected
    to be in integer representation

    >>> from sympy.logic.algorithms.dpll import find_pure_symbol_int_repr
    >>> find_pure_symbol_int_repr(set([1,2,3]),
    ...     [set([1, -2]), set([-2, -3]), set([3, 1])])
    (1, True)

    """
    all_symbols = reduce(set.union, unknown_clauses, set())
    found_pos = all_symbols.intersection(symbols)
    found_neg = all_symbols.intersection([-s for s in symbols])
    for p in found_pos:
        if -p not in found_neg:
            return p, True
    for p in found_neg:
        if -p not in found_pos:
            return -p, False
    return None, None
Ejemplo n.º 53
0
    def combine(c1, c2):
        """Return the tuple (a, m) which satisfies the requirement
        that n = a + i*m satisfy n = a1 + j*m1 and n = a2 = k*m2.

        References
        ==========

        - http://en.wikipedia.org/wiki/Method_of_successive_substitution
        """
        a1, m1 = c1
        a2, m2 = c2
        a, b, c = m1, a2 - a1, m2
        g = reduce(igcd, [a, b, c])
        a, b, c = [i // g for i in [a, b, c]]
        if a != 1:
            inv_a, _, g = igcdex(a, c)
            if g != 1:
                return None
            b *= inv_a
        a, m = a1 + m1 * b, m1 * c
        return a, m
Ejemplo n.º 54
0
def merge_explicit_mul(vecmul):
    """ Merge explicit Vector and Expr (Numbers, Symbols, ...) arguments
    Example
    ========
    >>> from sympy.vector import CoordSys3D
    >>> v1 = VectorSymbol("v1")
    >>> v2 = VectorSymbol("v2")
    >>> C = CoordSys3D("C")
    >>> vn1 = R.x * R.i + R.y * R.j + R.k * R.z
    >>> expr = VecMul(2, v1.mag, vn1, x, evaluate=False)
    >>> pprint(expr)
    2*x*(R.x*R.i + R.y*R.j + R.z*R.k)*Magnitude(VectorSymbol(v1))
    >>> pprint(merge_explicit(expr))
    (2*R.x*x*R.i + 2*R.y*x*R.j + 2*R.z*x*R.k)*Magnitude(VectorSymbol(v1))
    """

    groups = sift(vecmul.args, lambda arg: not isinstance(arg, VectorExpr))
    print("\t", groups)
    if len(groups[True]) > 1:
        return VecMul(*(groups[False] + [reduce(mul, groups[True])]))
    else:
        return vecmul
Ejemplo n.º 55
0
def merge_explicit(matadd):
    """ Merge explicit MatrixBase arguments
    >>> from sympy import MatrixSymbol, eye, Matrix, MatAdd, pprint
    >>> from sympy.matrices.expressions.matadd import merge_explicit
    >>> A = MatrixSymbol('A', 2, 2)
    >>> B = eye(2)
    >>> C = Matrix([[1, 2], [3, 4]])
    >>> X = MatAdd(A, B, C)
    >>> pprint(X)
        [1  0]   [1  2]
    A + [    ] + [    ]
        [0  1]   [3  4]
    >>> pprint(merge_explicit(X))
        [2  2]
    A + [    ]
        [3  5]
    """
    groups = sift(matadd.args, lambda arg: isinstance(arg, MatrixBase))
    if len(groups[True]) > 1:
        return SuperMatAdd(*(groups[False] + [reduce(add, groups[True])]))
    else:
        return matadd
def _get_indices_Mul(expr, return_dummies=False):
    """Determine the outer indices of a Mul object.

    Examples
    ========

    >>> from sympy.tensor.index_methods import _get_indices_Mul
    >>> from sympy.tensor.indexed import IndexedBase, Idx
    >>> i, j, k = map(Idx, ['i', 'j', 'k'])
    >>> x = IndexedBase('x')
    >>> y = IndexedBase('y')
    >>> _get_indices_Mul(x[i, k]*y[j, k])
    ({i, j}, {})
    >>> _get_indices_Mul(x[i, k]*y[j, k], return_dummies=True)
    ({i, j}, {}, (k,))

    """

    inds = list(map(get_indices, expr.args))
    inds, syms = list(zip(*inds))

    inds = list(map(list, inds))
    inds = list(reduce(lambda x, y: x + y, inds))
    inds, dummies = _remove_repeated(inds)

    symmetry = {}
    for s in syms:
        for pair in s:
            if pair in symmetry:
                symmetry[pair] *= s[pair]
            else:
                symmetry[pair] = s[pair]

    if return_dummies:
        return inds, symmetry, dummies
    else:
        return inds, symmetry
Ejemplo n.º 57
0
    def _eval_matrix_mul(self, other):
        """Fast multiplication exploiting the sparsity of the matrix."""

        if not isinstance(other, SparseMatrix):
            other = self._new(other)

        # if we made it here, we're both sparse matrices
        # create quick lookups for rows and cols
        row_lookup = defaultdict(dict)
        for (i, j), val in self._smat.items():
            row_lookup[i][j] = val
        col_lookup = defaultdict(dict)
        for (i, j), val in other._smat.items():
            col_lookup[j][i] = val

        smat = {}
        for row in row_lookup.keys():
            for col in col_lookup.keys():
                # find the common indices of non-zero entries.
                # these are the only things that need to be multiplied.
                indices = set(col_lookup[col].keys()) & set(
                    row_lookup[row].keys())
                if indices:
                    vec = [
                        row_lookup[row][k] * col_lookup[col][k]
                        for k in indices
                    ]
                    try:
                        smat[row, col] = Add(*vec)
                    except (TypeError, SympifyError):
                        # Some matrices don't work with `sum` or `Add`
                        # They don't work with `sum` because `sum` tries to add `0`
                        # Fall back to a safe way to multiply if the `Add` fails.
                        smat[row, col] = reduce(lambda a, b: a + b, vec)

        return self._new(self.rows, other.cols, smat)
Ejemplo n.º 58
0
def heurisch(f, x, rewrite=False, hints=None, mappings=None, retries=3):
    """
    Compute indefinite integral using heuristic Risch algorithm.

    This is a heuristic approach to indefinite integration in finite
    terms using the extended heuristic (parallel) Risch algorithm, based
    on Manuel Bronstein's "Poor Man's Integrator".

    The algorithm supports various classes of functions including
    transcendental elementary or special functions like Airy,
    Bessel, Whittaker and Lambert.

    Note that this algorithm is not a decision procedure. If it isn't
    able to compute the antiderivative for a given function, then this is
    not a proof that such a functions does not exist.  One should use
    recursive Risch algorithm in such case.  It's an open question if
    this algorithm can be made a full decision procedure.

    This is an internal integrator procedure. You should use toplevel
    'integrate' function in most cases,  as this procedure needs some
    preprocessing steps and otherwise may fail.

    Specification
    =============

     heurisch(f, x, rewrite=False, hints=None)

       where
         f : expression
         x : symbol

         rewrite -> force rewrite 'f' in terms of 'tan' and 'tanh'
         hints   -> a list of functions that may appear in anti-derivate

          - hints = None          --> no suggestions at all
          - hints = [ ]           --> try to figure out
          - hints = [f1, ..., fn] --> we know better

    Examples
    ========

    >>> from sympy import tan
    >>> from sympy.integrals.heurisch import heurisch
    >>> from sympy.abc import x, y

    >>> heurisch(y*tan(x), x)
    y*log(tan(x)**2 + 1)/2

    See Manuel Bronstein's "Poor Man's Integrator":

    [1] http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/index.html

    For more information on the implemented algorithm refer to:

    [2] K. Geddes, L. Stefanus, On the Risch-Norman Integration
       Method and its Implementation in Maple, Proceedings of
       ISSAC'89, ACM Press, 212-217.

    [3] J. H. Davenport, On the Parallel Risch Algorithm (I),
       Proceedings of EUROCAM'82, LNCS 144, Springer, 144-157.

    [4] J. H. Davenport, On the Parallel Risch Algorithm (III):
       Use of Tangents, SIGSAM Bulletin 16 (1982), 3-6.

    [5] J. H. Davenport, B. M. Trager, On the Parallel Risch
       Algorithm (II), ACM Transactions on Mathematical
       Software 11 (1985), 356-362.

    See Also
    ========

    sympy.integrals.integrals.Integral.doit
    sympy.integrals.integrals.Integral
    components
    """
    f = sympify(f)

    if not f.is_Add:
        indep, f = f.as_independent(x)
    else:
        indep = S.One

    if not f.has(x):
        return indep * f * x

    rewritables = {
        (sin, cos, cot): tan,
        (sinh, cosh, coth): tanh,
    }

    if rewrite:
        for candidates, rule in rewritables.iteritems():
            f = f.rewrite(candidates, rule)
    else:
        for candidates in rewritables.iterkeys():
            if f.has(*candidates):
                break
        else:
            rewrite = True

    terms = components(f, x)

    if hints is not None:
        if not hints:
            a = Wild('a', exclude=[x])
            b = Wild('b', exclude=[x])
            c = Wild('c', exclude=[x])

            for g in set(terms):
                if g.is_Function:
                    if g.func is exp:
                        M = g.args[0].match(a * x**2)

                        if M is not None:
                            terms.add(erf(sqrt(-M[a]) * x))

                        M = g.args[0].match(a * x**2 + b * x + c)

                        if M is not None:
                            if M[a].is_positive:
                                terms.add(
                                    sqrt(pi / 4 * (-M[a])) *
                                    exp(M[c] - M[b]**2 / (4 * M[a])) *
                                    erf(-sqrt(-M[a]) * x + M[b] /
                                        (2 * sqrt(-M[a]))))
                            elif M[a].is_negative:
                                terms.add(
                                    sqrt(pi / 4 * (-M[a])) *
                                    exp(M[c] - M[b]**2 / (4 * M[a])) * erf(
                                        sqrt(-M[a]) * x - M[b] /
                                        (2 * sqrt(-M[a]))))

                        M = g.args[0].match(a * log(x)**2)

                        if M is not None:
                            if M[a].is_positive:
                                terms.add(-I * erf(I *
                                                   (sqrt(M[a]) * log(x) + 1 /
                                                    (2 * sqrt(M[a])))))
                            if M[a].is_negative:
                                terms.add(
                                    erf(
                                        sqrt(-M[a]) * log(x) - 1 /
                                        (2 * sqrt(-M[a]))))

                elif g.is_Pow:
                    if g.exp.is_Rational and g.exp.q == 2:
                        M = g.base.match(a * x**2 + b)

                        if M is not None and M[b].is_positive:
                            if M[a].is_positive:
                                terms.add(asinh(sqrt(M[a] / M[b]) * x))
                            elif M[a].is_negative:
                                terms.add(asin(sqrt(-M[a] / M[b]) * x))

                        M = g.base.match(a * x**2 - b)

                        if M is not None and M[b].is_positive:
                            if M[a].is_positive:
                                terms.add(acosh(sqrt(M[a] / M[b]) * x))
                            elif M[a].is_negative:
                                terms.add((-M[b] / 2 * sqrt(-M[a]) * atan(
                                    sqrt(-M[a]) * x / sqrt(M[a] * x**2 - M[b]))
                                           ))

        else:
            terms |= set(hints)

    for g in set(terms):
        terms |= components(cancel(g.diff(x)), x)

    # TODO: caching is significant factor for why permutations work at all. Change this.
    V = _symbols('x', len(terms))

    mapping = dict(zip(terms, V))

    rev_mapping = {}

    for k, v in mapping.iteritems():
        rev_mapping[v] = k

    if mappings is None:
        # Pre-sort mapping in order of largest to smallest expressions (last is always x).
        def _sort_key(arg):
            return default_sort_key(arg[0].as_independent(x)[1])

        mapping = sorted(mapping.items(), key=_sort_key, reverse=True)
        mappings = permutations(mapping)

    def _substitute(expr):
        return expr.subs(mapping)

    for mapping in mappings:
        # TODO: optimize this by not generating permutations where mapping[-1] != x.
        if mapping[-1][0] != x:
            continue

        mapping = list(mapping)

        diffs = [_substitute(cancel(g.diff(x))) for g in terms]
        denoms = [g.as_numer_denom()[1] for g in diffs]

        if all(h.is_polynomial(*V)
               for h in denoms) and _substitute(f).is_rational_function(*V):
            denom = reduce(lambda p, q: lcm(p, q, *V), denoms)
            break
    else:
        if not rewrite:
            result = heurisch(f, x, rewrite=True, hints=hints)

            if result is not None:
                return indep * result

        return None

    numers = [cancel(denom * g) for g in diffs]

    def _derivation(h):
        return Add(*[d * h.diff(v) for d, v in zip(numers, V)])

    def _deflation(p):
        for y in V:
            if not p.has(y):
                continue

            if _derivation(p) is not S.Zero:
                c, q = p.as_poly(y).primitive()
                return _deflation(c) * gcd(q, q.diff(y)).as_expr()
        else:
            return p

    def _splitter(p):
        for y in V:
            if not p.has(y):
                continue

            if _derivation(y) is not S.Zero:
                c, q = p.as_poly(y).primitive()

                q = q.as_expr()

                h = gcd(q, _derivation(q), y)
                s = quo(h, gcd(q, q.diff(y), y), y)

                c_split = _splitter(c)

                if s.as_poly(y).degree() == 0:
                    return (c_split[0], q * c_split[1])

                q_split = _splitter(cancel(q / s))

                return (c_split[0] * q_split[0] * s, c_split[1] * q_split[1])
        else:
            return (S.One, p)

    special = {}

    for term in terms:
        if term.is_Function:
            if term.func is tan:
                special[1 + _substitute(term)**2] = False
            elif term.func is tanh:
                special[1 + _substitute(term)] = False
                special[1 - _substitute(term)] = False
            elif term.func is C.LambertW:
                special[_substitute(term)] = True

    F = _substitute(f)

    P, Q = F.as_numer_denom()

    u_split = _splitter(denom)
    v_split = _splitter(Q)

    polys = list(v_split) + [u_split[0]] + special.keys()

    s = u_split[0] * Mul(*[k for k, v in special.iteritems() if v])
    polified = [p.as_poly(*V) for p in [s, P, Q]]

    if None in polified:
        return None

    a, b, c = [p.total_degree() for p in polified]

    poly_denom = (s * v_split[0] * _deflation(v_split[1])).as_expr()

    def _exponent(g):
        if g.is_Pow:
            if g.exp.is_Rational and g.exp.q != 1:
                if g.exp.p > 0:
                    return g.exp.p + g.exp.q - 1
                else:
                    return abs(g.exp.p + g.exp.q)
            else:
                return 1
        elif not g.is_Atom and g.args:
            return max([_exponent(h) for h in g.args])
        else:
            return 1

    A, B = _exponent(f), a + max(b, c)

    if A > 1 and B > 1:
        monoms = monomials(V, A + B - 1)
    else:
        monoms = monomials(V, A + B)

    poly_coeffs = _symbols('A', len(monoms))

    poly_part = Add(
        *[poly_coeffs[i] * monomial for i, monomial in enumerate(monoms)])

    reducibles = set()

    for poly in polys:
        if poly.has(*V):
            try:
                factorization = factor(poly, greedy=True)
            except PolynomialError:
                factorization = poly
            factorization = poly

            if factorization.is_Mul:
                reducibles |= set(factorization.args)
            else:
                reducibles.add(factorization)

    def _integrate(field=None):
        irreducibles = set()

        for poly in reducibles:
            for z in poly.atoms(Symbol):
                if z in V:
                    break
            else:
                continue

            irreducibles |= set(root_factors(poly, z, filter=field))

        log_coeffs, log_part = [], []
        B = _symbols('B', len(irreducibles))

        for i, poly in enumerate(irreducibles):
            if poly.has(*V):
                log_coeffs.append(B[i])
                log_part.append(log_coeffs[-1] * log(poly))

        coeffs = poly_coeffs + log_coeffs

        candidate = poly_part / poly_denom + Add(*log_part)

        h = F - _derivation(candidate) / denom

        numer = h.as_numer_denom()[0].expand(force=True)

        equations = defaultdict(lambda: S.Zero)

        for term in Add.make_args(numer):
            coeff, dependent = term.as_independent(*V)
            equations[dependent] += coeff

        solution = solve(equations.values(), *coeffs)

        return (solution, candidate, coeffs) if solution else None

    if not (F.atoms(Symbol) - set(V)):
        result = _integrate('Q')

        if result is None:
            result = _integrate()
    else:
        result = _integrate()

    if result is not None:
        (solution, candidate, coeffs) = result

        antideriv = candidate.subs(solution)

        for coeff in coeffs:
            if coeff not in solution:
                antideriv = antideriv.subs(coeff, S.Zero)

        antideriv = antideriv.subs(rev_mapping)
        antideriv = cancel(antideriv).expand(force=True)

        if antideriv.is_Add:
            antideriv = antideriv.as_independent(x)[1]

        return indep * antideriv
    else:
        if retries >= 0:
            result = heurisch(f,
                              x,
                              mappings=mappings,
                              rewrite=rewrite,
                              hints=hints,
                              retries=retries - 1)

            if result is not None:
                return indep * result

        return None