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

    Examples
    ========

    >>> from diofant.solvers.inequalities import reduce_inequalities

    >>> x = Symbol('x', real=True)
    >>> y = Symbol('y', real=True)

    >>> reduce_inequalities(0 <= x + 3, [])
    -3 <= x
    >>> reduce_inequalities(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 == S.true:
            continue
        elif i == S.false:
            return S.false
        if i.lhs.is_number:
            raise NotImplementedError("Couldn't 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 = {
        i: Dummy(i.name, extended_real=True)
        for i in gens if i.is_extended_real is None
    }
    inequalities = [i.xreplace(recast) for i in inequalities]
    symbols = {i.xreplace(recast) for i in symbols}

    # solve system
    rv = _reduce_inequalities(inequalities, symbols)

    # restore original symbols and return
    return rv.xreplace({v: k for k, v in recast.items()})
Ejemplo n.º 2
0
def test_iterable_is_sequence():
    ordered = [[], (), Tuple(), Matrix([[]])]
    unordered = [set()]
    not_diofant_iterable = [{}, '']
    assert all(is_sequence(i) for i in ordered)
    assert all(not is_sequence(i) for i in unordered)
    assert all(iterable(i) for i in ordered + unordered)
    assert all(not iterable(i) for i in not_diofant_iterable)
    assert all(iterable(i, exclude=None) for i in not_diofant_iterable)
Ejemplo n.º 3
0
def test_iterable_is_sequence():
    ordered = [[], (), Tuple(), Matrix([[]])]
    unordered = [set()]
    not_diofant_iterable = [{}, '']
    assert all(is_sequence(i) for i in ordered)
    assert all(not is_sequence(i) for i in unordered)
    assert all(iterable(i) for i in ordered + unordered)
    assert all(not iterable(i) for i in not_diofant_iterable)
    assert all(iterable(i, exclude=None) for i in not_diofant_iterable)
Ejemplo n.º 4
0
    def __new__(cls, *args, **kwargs):
        evaluate = kwargs.get('evaluate', global_evaluate[0])

        if iterable(args[0]):
            if isinstance(args[0], Point) and not evaluate:
                return args[0]
            args = args[0]

        # unpack the arguments into a friendly Tuple
        # if we were already a Point, we're doing an excess
        # iteration, but we'll worry about efficiency later
        coords = Tuple(*args)
        if any(a.is_number and im(a) for a in coords):
            raise ValueError('Imaginary coordinates not permitted.')

        # Turn any Floats into rationals and simplify
        # any expressions before we instantiate
        if evaluate:
            coords = coords.xreplace(dict(
                [(f, simplify(nsimplify(f, rational=True)))
                for f in coords.atoms(Float)]))
        if len(coords) == 2:
            return Point2D(coords, **kwargs)
        if len(coords) == 3:
            return Point3D(coords, **kwargs)

        return GeometryEntity.__new__(cls, *coords)
Ejemplo n.º 5
0
    def _find_opts(expr):

        if expr.is_Atom or expr.is_Order:
            return

        if iterable(expr):
            list(map(_find_opts, expr))
            return

        if expr in seen_subexp:
            return expr
        seen_subexp.add(expr)

        list(map(_find_opts, expr.args))

        if _coeff_isneg(expr):
            neg_expr = -expr
            if not neg_expr.is_Atom:
                opt_subs[expr] = Mul(S.NegativeOne, neg_expr, evaluate=False)
                seen_subexp.add(neg_expr)
                expr = neg_expr

        if expr.is_Mul:
            muls.add(expr)

        elif expr.is_Add:
            adds.add(expr)

        elif expr.is_Pow:
            if _coeff_isneg(expr.exp):
                opt_subs[expr] = Pow(Pow(expr.base, -expr.exp),
                                     S.NegativeOne,
                                     evaluate=False)
Ejemplo n.º 6
0
    def convert(self, elem, M=None):
        """
        Convert ``elem`` into the internal representation.

        This method is called implicitly whenever computations involve elements
        not in the internal representation.

        >>> from diofant.abc import x
        >>> from diofant import QQ
        >>> F = QQ.old_poly_ring(x).free_module(2)
        >>> F.convert([1, 0])
        [1, 0]
        """
        if isinstance(elem, FreeModuleElement):
            if elem.module is self:
                return elem
            if elem.module.rank != self.rank:
                raise CoercionFailed
            return FreeModuleElement(
                self,
                tuple(
                    self.ring.convert(x, elem.module.ring) for x in elem.data))
        elif iterable(elem):
            tpl = tuple(self.ring.convert(x) for x in elem)
            if len(tpl) != self.rank:
                raise CoercionFailed
            return FreeModuleElement(self, tpl)
        elif elem is 0:
            return FreeModuleElement(self,
                                     (self.ring.convert(0), ) * self.rank)
        else:
            raise CoercionFailed
Ejemplo n.º 7
0
def posify(eq):
    """Return eq (with generic symbols made positive) and a
    dictionary containing the mapping between the old and new
    symbols.

    Any symbol that has positive=None will be replaced with a positive dummy
    symbol having the same name. This replacement will allow more symbolic
    processing of expressions, especially those involving powers and
    logarithms.

    A dictionary that can be sent to subs to restore eq to its original
    symbols is also returned.

    >>> from diofant import posify, Symbol, log, solve
    >>> from diofant.abc import x
    >>> posify(x + Symbol('p', positive=True) + Symbol('n', negative=True))
    (n + p + _x, {_x: x})

    >>> eq = 1/x
    >>> log(eq).expand()
    log(1/x)
    >>> log(posify(eq)[0]).expand()
    -log(_x)
    >>> p, rep = posify(eq)
    >>> log(p).expand().subs(rep)
    -log(x)

    It is possible to apply the same transformations to an iterable
    of expressions:

    >>> eq = x**2 - 4
    >>> solve(eq, x)
    [-2, 2]
    >>> eq_x, reps = posify([eq, x]); eq_x
    [_x**2 - 4, _x]
    >>> solve(*eq_x)
    [2]
    """
    eq = sympify(eq)
    if iterable(eq):
        f = type(eq)
        eq = list(eq)
        syms = set()
        for e in eq:
            syms = syms.union(e.atoms(Symbol))
        reps = {}
        for s in syms:
            reps.update({v: k for k, v in posify(s)[1].items()})
        for i, e in enumerate(eq):
            eq[i] = e.subs(reps)
        return f(eq), {r: s for s, r in reps.items()}

    reps = {
        s: Dummy(s.name, positive=True)
        for s in eq.free_symbols if s.is_positive is None
    }
    eq = eq.subs(reps)
    return eq, {r: s for s, r in reps.items()}
Ejemplo n.º 8
0
    def __init__(self, monom, gens=None):
        if not iterable(monom):
            rep, gens = dict_from_expr(sympify(monom), gens=gens)
            if len(rep) == 1 and list(rep.values())[0] == 1:
                monom = list(rep.keys())[0]
            else:
                raise ValueError("Expected a monomial got %s" % monom)

        self.exponents = tuple(map(int, monom))
        self.gens = gens
Ejemplo n.º 9
0
    def __new__(cls, *args, **kw_args):
        """The constructor for the Prufer object.

        Examples
        ========

        >>> from diofant.combinatorics.prufer import Prufer

        A Prufer object can be constructed from a list of edges:

        >>> a = Prufer([[0, 1], [0, 2], [0, 3]])
        >>> a.prufer_repr
        [0, 0]

        If the number of nodes is given, no checking of the nodes will
        be performed; it will be assumed that nodes 0 through n - 1 are
        present:

        >>> Prufer([[0, 1], [0, 2], [0, 3]], 4)
        Prufer([[0, 1], [0, 2], [0, 3]], 4)

        A Prufer object can be constructed from a Prufer sequence:

        >>> b = Prufer([1, 3])
        >>> b.tree_repr
        [[0, 1], [1, 3], [2, 3]]

        """
        ret_obj = Basic.__new__(cls, *args, **kw_args)
        args = [list(args[0])]
        if args[0] and iterable(args[0][0]):
            if not args[0][0]:
                raise ValueError(
                    'Prufer expects at least one edge in the tree.')
            if len(args) > 1:
                nnodes = args[1]
            else:
                nodes = set(flatten(args[0]))
                nnodes = max(nodes) + 1
                if nnodes != len(nodes):
                    missing = set(range(nnodes)) - nodes
                    if len(missing) == 1:
                        msg = 'Node %s is missing.' % missing.pop()
                    else:
                        msg = 'Nodes %s are missing.' % list(sorted(missing))
                    raise ValueError(msg)
            ret_obj._tree_repr = [list(i) for i in args[0]]
            ret_obj._nodes = nnodes
        else:
            ret_obj._prufer_repr = args[0]
            ret_obj._nodes = len(ret_obj._prufer_repr) + 2
        return ret_obj
Ejemplo n.º 10
0
    def __add__(self, other):
        """Add other to self by incrementing self's coordinates by those of other.

        See Also
        ========

        diofant.geometry.entity.GeometryEntity.translate
        """

        if iterable(other) and len(other) == len(self):
            return Point([simplify(a + b) for a, b in zip(self, other)])
        else:
            raise ValueError(
                "Points must have the same number of dimensions")
Ejemplo n.º 11
0
    def _rebuild(expr):

        if not expr.args:
            return expr

        if iterable(expr):
            new_args = [_rebuild(arg) for arg in expr]
            return expr.func(*new_args)

        if expr in subs:
            return subs[expr]

        orig_expr = expr
        if expr in opt_subs:
            expr = opt_subs[expr]

        # If enabled, parse Muls and Adds arguments by order to ensure
        # replacement order independent from hashes
        if order != 'none':
            if expr.is_Mul:
                c, nc = expr.args_cnc()
                args = list(ordered(c)) + nc
            elif expr.is_Add:
                args = list(ordered(expr.args))
            else:
                args = expr.args
        else:
            args = expr.args

        new_args = list(map(_rebuild, args))
        if new_args != args:
            new_expr = expr.func(*new_args)
        else:
            new_expr = expr

        if orig_expr in to_eliminate:
            try:
                sym = next(symbols)
            except StopIteration:
                raise ValueError("Symbols iterator ran out of symbols.")
            subs[orig_expr] = sym
            replacements.append((sym, new_expr))
            return sym

        else:
            return new_expr
Ejemplo n.º 12
0
def _nodes(e):
    """
    A helper for ordered() which returns the node count of ``e`` which
    for Basic objects is the number of Basic nodes in the expression tree
    but for other objects is 1 (unless the object is an iterable or dict
    for which the sum of nodes is returned).
    """
    from .basic import Basic

    if isinstance(e, Basic):
        return e.count(Basic)
    elif iterable(e):
        return 1 + sum(_nodes(ei) for ei in e)
    elif isinstance(e, dict):
        return 1 + sum(_nodes(k) + _nodes(v) for k, v in e.items())
    else:
        return 1
Ejemplo n.º 13
0
 def parse_hints(hints):
     """Split hints into (n, funcs, iterables, gens)."""
     n = 1
     funcs, iterables, gens = [], [], []
     for e in hints:
         if isinstance(e, (int, Integer)):
             n = e
         elif isinstance(e, FunctionClass):
             funcs.append(e)
         elif iterable(e):
             iterables.append((e[0], e[1:]))
             # XXX sin(x+2y)?
             # Note: we go through polys so e.g.
             # sin(-x) -> -sin(x) -> sin(x)
             gens.extend(
                 parallel_poly_from_expr([e[0](x) for x in e[1:]] +
                                         [e[0](Add(*e[1:]))])[1].gens)
         else:
             gens.append(e)
     return n, funcs, iterables, gens
Ejemplo n.º 14
0
    def _find_repeated(expr):
        if expr.is_Atom or expr.is_Order:
            return

        if iterable(expr):
            args = expr

        else:
            if expr in seen_subexp:
                to_eliminate.add(expr)
                return

            seen_subexp.add(expr)

            if expr in opt_subs:
                expr = opt_subs[expr]

            args = expr.args

        list(map(_find_repeated, args))
Ejemplo n.º 15
0
 def __new__(cls, *args, **kwargs):
     eval = kwargs.get('evaluate', global_evaluate[0])
     if isinstance(args[0], (Point, Point3D)):
         if not eval:
             return args[0]
         args = args[0].args
     else:
         if iterable(args[0]):
             args = args[0]
         if len(args) not in (2, 3):
             raise TypeError(
                 "Enter a 2 or 3 dimensional point")
     coords = Tuple(*args)
     if len(coords) == 2:
         coords += (S.Zero,)
     if eval:
         coords = coords.xreplace(dict(
             [(f, simplify(nsimplify(f, rational=True)))
             for f in coords.atoms(Float)]))
     return GeometryEntity.__new__(cls, *coords)
Ejemplo n.º 16
0
    def _together(expr):
        if isinstance(expr, Basic):
            if expr.is_Atom or (expr.is_Function and not deep):
                return expr
            elif expr.is_Add:
                return gcd_terms(list(map(_together, Add.make_args(expr))))
            elif expr.is_Pow:
                base = _together(expr.base)

                if deep:
                    exp = _together(expr.exp)
                else:
                    exp = expr.exp

                return expr.__class__(base, exp)
            else:
                return expr.__class__(*[_together(arg) for arg in expr.args])
        elif iterable(expr):
            return expr.__class__([_together(ex) for ex in expr])

        return expr
Ejemplo n.º 17
0
def is_sequence(i, include=None):
    """
    Return a boolean indicating whether ``i`` is a sequence in the Diofant
    sense. If anything that fails the test below should be included as
    being a sequence for your application, set 'include' to that object's
    type; multiple types should be passed as a tuple of types.

    Note: although generators can generate a sequence, they often need special
    handling to make sure their elements are captured before the generator is
    exhausted, so these are not included by default in the definition of a
    sequence.

    See Also
    ========

    iterable

    Examples
    ========

    >>> from diofant.utilities.iterables import is_sequence
    >>> from types import GeneratorType
    >>> is_sequence([])
    True
    >>> is_sequence(set())
    False
    >>> is_sequence('abc')
    False
    >>> is_sequence('abc', include=str)
    True
    >>> generator = (c for c in 'abc')
    >>> is_sequence(generator)
    False
    >>> is_sequence(generator, include=(str, GeneratorType))
    True
    """
    return (hasattr(i, '__getitem__') and iterable(i)
            or bool(include) and isinstance(i, include))
Ejemplo n.º 18
0
 def __new__(cls, *args, **kwargs):
     eval = kwargs.get('evaluate', global_evaluate[0])
     check = True
     if isinstance(args[0], Point2D):
         if not eval:
             return args[0]
         args = args[0].args
         check = False
     else:
         if iterable(args[0]):
             args = args[0]
         if len(args) != 2:
             raise ValueError(
                 "Only two dimensional points currently supported")
     coords = Tuple(*args)
     if check:
         if any(a.is_number and im(a) for a in coords):
             raise ValueError('Imaginary args not permitted.')
     if eval:
         coords = coords.xreplace(dict(
             [(f, simplify(nsimplify(f, rational=True)))
             for f in coords.atoms(Float)]))
     return GeometryEntity.__new__(cls, *coords)
Ejemplo n.º 19
0
def as_finite_diff(derivative, points=1, x0=None, wrt=None):
    """
    Returns an approximation of a derivative of a function in
    the form of a finite difference formula. The expression is a
    weighted sum of the function at a number of discrete values of
    (one of) the independent variable(s).

    Parameters
    ==========

    derivative: a Derivative instance (needs to have an variables
        and expr attribute).

    points: sequence or coefficient, optional
        If sequence: discrete values (length >= order+1) of the
        independent variable used for generating the finite
        difference weights.
        If it is a coefficient, it will be used as the step-size
        for generating an equidistant sequence of length order+1
        centered around x0. default: 1 (step-size 1)

    x0: number or Symbol, optional
        the value of the independent variable (wrt) at which the
        derivative is to be approximated. default: same as wrt

    wrt: Symbol, optional
        "with respect to" the variable for which the (partial)
        derivative is to be approximated for. If not provided it
        is required that the Derivative is ordinary. default: None


    Examples
    ========

    >>> from diofant import symbols, Function, exp, sqrt, Symbol, as_finite_diff
    >>> x, h = symbols('x h')
    >>> f = Function('f')
    >>> as_finite_diff(f(x).diff(x))
    -f(x - 1/2) + f(x + 1/2)

    The default step size and number of points are 1 and ``order + 1``
    respectively. We can change the step size by passing a symbol
    as a parameter:

    >>> as_finite_diff(f(x).diff(x), h)
    -f(-h/2 + x)/h + f(h/2 + x)/h

    We can also specify the discretized values to be used in a sequence:

    >>> as_finite_diff(f(x).diff(x), [x, x+h, x+2*h])
    -3*f(x)/(2*h) + 2*f(h + x)/h - f(2*h + x)/(2*h)

    The algorithm is not restricted to use equidistant spacing, nor
    do we need to make the approximation around x0, but we can get
    an expression estimating the derivative at an offset:

    >>> e, sq2 = exp(1), sqrt(2)
    >>> xl = [x-h, x+h, x+e*h]
    >>> as_finite_diff(f(x).diff(x, 1), xl, x+h*sq2)
    2*h*f(E*h + x)*((h + sqrt(2)*h)/(2*h) -\
    (-sqrt(2)*h + h)/(2*h))/((-h + E*h)*(h + E*h)) +\
    f(-h + x)*(-(-sqrt(2)*h + h)/(2*h) - (-sqrt(2)*h + E*h)/(2*h))/(h +\
    E*h) + f(h + x)*(-(h + sqrt(2)*h)/(2*h) + (-sqrt(2)*h +\
    E*h)/(2*h))/(-h + E*h)

    Partial derivatives are also supported:

    >>> y = Symbol('y')
    >>> d2fdxdy=f(x,y).diff(x,y)
    >>> as_finite_diff(d2fdxdy, wrt=x)
    -f(x - 1/2, y) + f(x + 1/2, y)

    See also
    ========

    diofant.calculus.finite_diff.apply_finite_diff
    diofant.calculus.finite_diff.finite_diff_weights

    """
    if wrt is None:
        wrt = derivative.variables[0]
        # we need Derivative to be univariate to guess wrt
        if any(v != wrt for v in derivative.variables):
            raise ValueError('if the function is not univariate' +
                             ' then `wrt` must be given')

    order = derivative.variables.count(wrt)

    if x0 is None:
        x0 = wrt

    if not iterable(points):
        # points is simply the step-size, let's make it a
        # equidistant sequence centered around x0
        if order % 2 == 0:
            # even order => odd number of points, grid point included
            points = [
                x0 + points * i for i in range(-order // 2, order // 2 + 1)
            ]
        else:
            # odd order => even number of points, half-way wrt grid point
            points = [
                x0 + points * i / Integer(2)
                for i in range(-order, order + 1, 2)
            ]

    if len(points) < order + 1:
        raise ValueError("Too few points for order %d" % order)
    return apply_finite_diff(order, points,
                             [derivative.expr.subs({wrt: x}) for x in points],
                             x0)
Ejemplo n.º 20
0
def collect(expr,
            syms,
            func=None,
            evaluate=True,
            exact=False,
            distribute_order_term=True):
    """Collect additive terms of an expression.

    This function collects additive terms of an expression with respect
    to a list of expression up to powers with rational exponents. By the
    term symbol here are meant arbitrary expressions, which can contain
    powers, products, sums etc. In other words symbol is a pattern which
    will be searched for in the expression's terms.

    The input expression is not expanded by :func:`collect`, so user is
    expected to provide an expression is an appropriate form (for example,
    by using :func:`~diofant.core.function.expand` prior to calling this
    function). This makes :func:`collect` more predictable as there is no
    magic happening behind the scenes. However, it is important to note,
    that powers of products are converted to products of powers using the
    :func:`~diofant.core.function.expand_power_base` function.

    Parameters
    ==========

    expr : Expr
        an expression
    syms : iterable of Symbol's
        collected symbols
    evaluate : boolean
        First, if ``evaluate`` flag is set (by default), this function will
        return an expression with collected terms else it will return a
        dictionary with expressions up to rational powers as keys and
        collected coefficients as values.

    Examples
    ========

    >>> from diofant import collect, expand, factor
    >>> from diofant.abc import a, b, c, x, y

    This function can collect symbolic coefficients in polynomials or
    rational expressions. It will manage to find all integer or rational
    powers of collection variable:

    >>> collect(a*x**2 + b*x**2 + a*x - b*x + c, x)
    c + x**2*(a + b) + x*(a - b)

    The same result can be achieved in dictionary form:

    >>> d = collect(a*x**2 + b*x**2 + a*x - b*x + c, x, evaluate=False)
    >>> d[x**2]
    a + b
    >>> d[x]
    a - b
    >>> d[1]
    c

    You can also work with multivariate polynomials. However, remember that
    this function is greedy so it will care only about a single symbol at time,
    in specification order:

    >>> collect(x**2 + y*x**2 + x*y + y + a*y, [x, y])
    x**2*(y + 1) + x*y + y*(a + 1)

    Also more complicated expressions can be used as patterns:

    >>> from diofant import sin, log
    >>> collect(a*sin(2*x) + b*sin(2*x), sin(2*x))
    (a + b)*sin(2*x)

    >>> collect(a*x*log(x) + b*(x*log(x)), x*log(x))
    x*(a + b)*log(x)

    You can use wildcards in the pattern:

    >>> from diofant import Wild
    >>> w = Wild('w1')
    >>> collect(a*x**y - b*x**y, w**y)
    x**y*(a - b)

    It is also possible to work with symbolic powers, although it has more
    complicated behavior, because in this case power's base and symbolic part
    of the exponent are treated as a single symbol:

    >>> collect(a*x**c + b*x**c, x)
    a*x**c + b*x**c
    >>> collect(a*x**c + b*x**c, x**c)
    x**c*(a + b)

    However if you incorporate rationals to the exponents, then you will get
    well known behavior:

    >>> collect(a*x**(2*c) + b*x**(2*c), x**c)
    x**(2*c)*(a + b)

    Note also that all previously stated facts about :func:`collect` function
    apply to the exponential function, so you can get:

    >>> from diofant import exp
    >>> collect(a*exp(2*x) + b*exp(2*x), exp(x))
    E**(2*x)*(a + b)

    If you are interested only in collecting specific powers of some symbols
    then set ``exact`` flag in arguments:

    >>> collect(a*x**7 + b*x**7, x, exact=True)
    a*x**7 + b*x**7
    >>> collect(a*x**7 + b*x**7, x**7, exact=True)
    x**7*(a + b)

    You can also apply this function to differential equations, where
    derivatives of arbitrary order can be collected. Note that if you
    collect with respect to a function or a derivative of a function, all
    derivatives of that function will also be collected. Use
    ``exact=True`` to prevent this from happening:

    >>> from diofant import Derivative as D, Function
    >>> f = Function('f')(x)

    >>> collect(a*D(f,x) + b*D(f,x), D(f,x))
    (a + b)*Derivative(f(x), x)

    >>> collect(a*D(D(f,x),x) + b*D(D(f,x),x), f)
    (a + b)*Derivative(f(x), x, x)

    >>> collect(a*D(D(f,x),x) + b*D(D(f,x),x), D(f,x), exact=True)
    a*Derivative(f(x), x, x) + b*Derivative(f(x), x, x)

    >>> collect(a*D(f,x) + b*D(f,x) + a*f + b*f, f)
    f(x)*(a + b) + (a + b)*Derivative(f(x), x)

    Or you can even match both derivative order and exponent at the same time:

    >>> collect(a*D(D(f,x),x)**2 + b*D(D(f,x),x)**2, D(f,x))
    (a + b)*Derivative(f(x), x, x)**2

    Finally, you can apply a function to each of the collected coefficients.
    For example you can factorize symbolic coefficients of polynomial:

    >>> f = expand((x + a + 1)**3)

    >>> collect(f, x, factor)
    x**3 + 3*x**2*(a + 1) + 3*x*(a + 1)**2 + (a + 1)**3

    See Also
    ========

    collect_const, collect_sqrt, rcollect
    """
    def make_expression(terms):
        product = []

        for term, rat, sym, deriv in terms:
            if deriv is not None:
                var, order = deriv

                while order > 0:
                    term, order = Derivative(term, var), order - 1

            if sym is None:
                if rat is S.One:
                    product.append(term)
                else:
                    product.append(Pow(term, rat))
            else:
                product.append(Pow(term, rat * sym))

        return Mul(*product)

    def parse_derivative(deriv):
        # scan derivatives tower in the input expression and return
        # underlying function and maximal differentiation order
        expr, sym, order = deriv.expr, deriv.variables[0], 1

        for s in deriv.variables[1:]:
            if s == sym:
                order += 1
            else:
                raise NotImplementedError(
                    'Improve MV Derivative support in collect')

        while isinstance(expr, Derivative):
            s0 = expr.variables[0]

            for s in expr.variables:
                if s != s0:
                    raise NotImplementedError(
                        'Improve MV Derivative support in collect')

            if s0 == sym:
                expr, order = expr.expr, order + len(expr.variables)
            else:
                break

        return expr, (sym, Rational(order))

    def parse_term(expr):
        """Parses expression expr and outputs tuple (sexpr, rat_expo,
        sym_expo, deriv)
        where:
         - sexpr is the base expression
         - rat_expo is the rational exponent that sexpr is raised to
         - sym_expo is the symbolic exponent that sexpr is raised to
         - deriv contains the derivatives the the expression

         for example, the output of x would be (x, 1, None, None)
         the output of 2**x would be (2, 1, x, None)
        """
        rat_expo, sym_expo = S.One, None
        sexpr, deriv = expr, None

        if expr.is_Pow:
            if isinstance(expr.base, Derivative):
                sexpr, deriv = parse_derivative(expr.base)
            else:
                sexpr = expr.base

            if expr.exp.is_Number:
                rat_expo = expr.exp
            else:
                coeff, tail = expr.exp.as_coeff_Mul()

                if coeff.is_Number:
                    rat_expo, sym_expo = coeff, tail
                else:
                    sym_expo = expr.exp
        elif isinstance(expr, Derivative):
            sexpr, deriv = parse_derivative(expr)

        return sexpr, rat_expo, sym_expo, deriv

    def parse_expression(terms, pattern):
        """Parse terms searching for a pattern.
        terms is a list of tuples as returned by parse_terms;
        pattern is an expression treated as a product of factors
        """
        pattern = Mul.make_args(pattern)

        if len(terms) < len(pattern):
            # pattern is longer than matched product
            # so no chance for positive parsing result
            return
        else:
            pattern = [parse_term(elem) for elem in pattern]

            terms = terms[:]  # need a copy
            elems, common_expo, has_deriv = [], None, False

            for elem, e_rat, e_sym, e_ord in pattern:

                if elem.is_Number and e_rat == 1 and e_sym is None:
                    # a constant is a match for everything
                    continue

                for j in range(len(terms)):
                    if terms[j] is None:
                        continue

                    term, t_rat, t_sym, t_ord = terms[j]

                    # keeping track of whether one of the terms had
                    # a derivative or not as this will require rebuilding
                    # the expression later
                    if t_ord is not None:
                        has_deriv = True

                    if (term.match(elem) is not None
                            and (t_sym == e_sym
                                 or t_sym is not None and e_sym is not None
                                 and t_sym.match(e_sym) is not None)):
                        if exact is False:
                            # we don't have to be exact so find common exponent
                            # for both expression's term and pattern's element
                            expo = t_rat / e_rat

                            if common_expo is None:
                                # first time
                                common_expo = expo
                            else:
                                # common exponent was negotiated before so
                                # there is no chance for a pattern match unless
                                # common and current exponents are equal
                                if common_expo != expo:
                                    common_expo = 1
                        else:
                            # we ought to be exact so all fields of
                            # interest must match in every details
                            if e_rat != t_rat or e_ord != t_ord:
                                continue

                        # found common term so remove it from the expression
                        # and try to match next element in the pattern
                        elems.append(terms[j])
                        terms[j] = None

                        break

                else:
                    # pattern element not found
                    return

            return [_f for _f in terms if _f], elems, common_expo, has_deriv

    if evaluate:
        if expr.is_Mul:
            return expr.func(*[
                collect(term, syms, func, True, exact, distribute_order_term)
                for term in expr.args
            ])
        elif expr.is_Pow:
            b = collect(expr.base, syms, func, True, exact,
                        distribute_order_term)
            return Pow(b, expr.exp)

    if iterable(syms):
        syms = [expand_power_base(i, deep=False) for i in syms]
    else:
        syms = [expand_power_base(syms, deep=False)]

    expr = sympify(expr)
    order_term = None

    if distribute_order_term:
        order_term = expr.getO()

        if order_term is not None:
            if order_term.has(*syms):
                order_term = None
            else:
                expr = expr.removeO()

    summa = [expand_power_base(i, deep=False) for i in Add.make_args(expr)]

    collected, disliked = defaultdict(list), S.Zero
    for product in summa:
        terms = [parse_term(i) for i in Mul.make_args(product)]

        for symbol in syms:
            if DIOFANT_DEBUG:
                print("DEBUG: parsing of expression %s with symbol %s " %
                      (str(terms), str(symbol)))

            result = parse_expression(terms, symbol)

            if DIOFANT_DEBUG:
                print("DEBUG: returned %s" % str(result))

            if result is not None:
                terms, elems, common_expo, has_deriv = result

                # when there was derivative in current pattern we
                # will need to rebuild its expression from scratch
                if not has_deriv:
                    index = 1
                    for elem in elems:
                        e = elem[1]
                        if elem[2] is not None:
                            e *= elem[2]
                        index *= Pow(elem[0], e)
                else:
                    index = make_expression(elems)
                terms = expand_power_base(make_expression(terms), deep=False)
                index = expand_power_base(index, deep=False)
                collected[index].append(terms)
                break
        else:
            # none of the patterns matched
            disliked += product
    # add terms now for each key
    collected = {k: Add(*v) for k, v in collected.items()}

    if disliked is not S.Zero:
        collected[S.One] = disliked

    if order_term is not None:
        for key, val in collected.items():
            collected[key] = val + order_term

    if func is not None:
        collected = dict([(key, func(val)) for key, val in collected.items()])

    if evaluate:
        return Add(*[key * val for key, val in collected.items()])
    else:
        return collected
Ejemplo n.º 21
0
def default_sort_key(item, order=None):
    """
    Return a key that can be used for sorting.

    The key has the structure:

    (class_key, (len(args), args), exponent.sort_key(), coefficient)

    This key is supplied by the sort_key routine of Basic objects when
    ``item`` is a Basic object or an object (other than a string) that
    sympifies to a Basic object. Otherwise, this function produces the
    key.

    The ``order`` argument is passed along to the sort_key routine and is
    used to determine how the terms *within* an expression are ordered.
    (See examples below) ``order`` options are: 'lex', 'grlex', 'grevlex',
    and reversed values of the same (e.g. 'rev-lex'). The default order
    value is None (which translates to 'lex').

    Examples
    ========

    >>> from diofant import S, I, default_sort_key, sin, cos, sqrt
    >>> from diofant.core.function import UndefinedFunction
    >>> from diofant.abc import x

    The following are equivalent ways of getting the key for an object:

    >>> x.sort_key() == default_sort_key(x)
    True

    Here are some examples of the key that is produced:

    >>> default_sort_key(UndefinedFunction('f'))
    ((0, 0, 'UndefinedFunction'), (1, ('f',)), ((1, 0, 'Number'),
        (0, ()), (), 1), 1)
    >>> default_sort_key('1')
    ((0, 0, 'str'), (1, ('1',)), ((1, 0, 'Number'), (0, ()), (), 1), 1)
    >>> default_sort_key(S.One)
    ((1, 0, 'Number'), (0, ()), (), 1)
    >>> default_sort_key(2)
    ((1, 0, 'Number'), (0, ()), (), 2)

    While sort_key is a method only defined for Diofant objects,
    default_sort_key will accept anything as an argument so it is
    more robust as a sorting key. For the following, using key=
    lambda i: i.sort_key() would fail because 2 doesn't have a sort_key
    method; that's why default_sort_key is used. Note, that it also
    handles sympification of non-string items likes ints:

    >>> a = [2, I, -I]
    >>> sorted(a, key=default_sort_key)
    [2, -I, I]

    The returned key can be used anywhere that a key can be specified for
    a function, e.g. sort, min, max, etc...:

    >>> a.sort(key=default_sort_key); a[0]
    2
    >>> min(a, key=default_sort_key)
    2

    Notes
    =====

    The key returned is useful for getting items into a canonical order
    that will be the same across platforms. It is not directly useful for
    sorting lists of expressions:

    >>> a, b = x, 1/x

    Since ``a`` has only 1 term, its value of sort_key is unaffected by
    ``order``:

    >>> a.sort_key() == a.sort_key('rev-lex')
    True

    If ``a`` and ``b`` are combined then the key will differ because there
    are terms that can be ordered:

    >>> eq = a + b
    >>> eq.sort_key() == eq.sort_key('rev-lex')
    False
    >>> eq.as_ordered_terms()
    [x, 1/x]
    >>> eq.as_ordered_terms('rev-lex')
    [1/x, x]

    But since the keys for each of these terms are independent of ``order``'s
    value, they don't sort differently when they appear separately in a list:

    >>> sorted(eq.args, key=default_sort_key)
    [1/x, x]
    >>> sorted(eq.args, key=lambda i: default_sort_key(i, order='rev-lex'))
    [1/x, x]

    The order of terms obtained when using these keys is the order that would
    be obtained if those terms were *factors* in a product.

    Although it is useful for quickly putting expressions in canonical order,
    it does not sort expressions based on their complexity defined by the
    number of operations, power of variables and others:

    >>> sorted([sin(x)*cos(x), sin(x)], key=default_sort_key)
    [sin(x)*cos(x), sin(x)]
    >>> sorted([x, x**2, sqrt(x), x**3], key=default_sort_key)
    [sqrt(x), x, x**2, x**3]

    See Also
    ========

    ordered
    diofant.core.expr.Expr.as_ordered_factors
    diofant.core.expr.Expr.as_ordered_terms
    """
    from diofant.core import S, Basic
    from diofant.core.sympify import sympify, SympifyError
    from diofant.core.compatibility import iterable

    if isinstance(item, Basic):
        return item.sort_key(order=order)

    if iterable(item, exclude=(str, )):
        if isinstance(item, dict):
            args = item.items()
            unordered = True
        elif isinstance(item, set):
            args = item
            unordered = True
        else:
            # e.g. tuple, list
            args = list(item)
            unordered = False

        args = [default_sort_key(arg, order=order) for arg in args]

        if unordered:  # e.g. dict, set
            args = sorted(args)

        cls_index, args = 10, (len(args), tuple(args))
    else:
        if not isinstance(item, str):
            try:
                item = sympify(item)
            except SympifyError:
                # e.g. lambda x: x
                pass
            else:
                if isinstance(item, Basic):
                    # e.g int -> Integer
                    return default_sort_key(item)
                # e.g. UndefinedFunction

        # e.g. str
        cls_index, args = 0, (1, (str(item), ))

    return (cls_index, 0,
            item.__class__.__name__), args, S.One.sort_key(), S.One
Ejemplo n.º 22
0
def test_not_interable():
    i, j = symbols('i j', integer=True)
    A = Indexed('A', i, i + j)
    assert not iterable(A)
Ejemplo n.º 23
0
def euler_equations(L, funcs=(), vars=()):
    r"""
    Find the Euler-Lagrange equations [1]_ for a given Lagrangian.

    Parameters
    ==========

    L : Expr
        The Lagrangian that should be a function of the functions listed
        in the second argument and their derivatives.

        For example, in the case of two functions `f(x,y)`, `g(x,y)` and
        two independent variables `x`, `y` the Lagrangian would have the form:

            .. math:: L\left(f(x,y),g(x,y),\frac{\partial f(x,y)}{\partial x},
                      \frac{\partial f(x,y)}{\partial y},
                      \frac{\partial g(x,y)}{\partial x},
                      \frac{\partial g(x,y)}{\partial y},x,y\right)

        In many cases it is not necessary to provide anything, except the
        Lagrangian, it will be auto-detected (and an error raised if this
        couldn't be done).

    funcs : Function or an iterable of Functions
        The functions that the Lagrangian depends on. The Euler equations
        are differential equations for each of these functions.

    vars : Symbol or an iterable of Symbols
        The Symbols that are the independent variables of the functions.

    Returns
    =======

    eqns : list of Eq
        The list of differential equations, one for each function.

    Examples
    ========

    >>> from diofant import Symbol, Function

    >>> x = Function('x')
    >>> t = Symbol('t')
    >>> L = (x(t).diff(t))**2/2 - x(t)**2/2
    >>> euler_equations(L, x(t), t)
    [Eq(-x(t) - Derivative(x(t), t, t), 0)]
    >>> u = Function('u')
    >>> x = Symbol('x')
    >>> L = (u(t, x).diff(t))**2/2 - (u(t, x).diff(x))**2/2
    >>> euler_equations(L, u(t, x), [t, x])
    [Eq(-Derivative(u(t, x), t, t) + Derivative(u(t, x), x, x), 0)]

    References
    ==========

    .. [1] http://en.wikipedia.org/wiki/Euler%E2%80%93Lagrange_equation
    """
    L = sympify(L)
    funcs = tuple(funcs) if iterable(funcs) else (funcs, )

    if not funcs:
        funcs = tuple(L.atoms(Function))
    else:
        for f in funcs:
            if not isinstance(f, Function):
                raise TypeError('Function expected, got: %s' % f)

    vars = tuple(vars) if iterable(vars) else (vars, )

    if not vars:
        vars = funcs[0].args
    else:
        vars = tuple(sympify(var) for var in vars)

    if not all(isinstance(v, Symbol) for v in vars):
        raise TypeError('Variables are not symbols, got %s' % vars)

    for f in funcs:
        if not vars == f.args:
            raise ValueError("Variables %s don't match args: %s" % (vars, f))

    order = max(
        len(d.variables) for d in L.atoms(Derivative) if d.expr in funcs)

    eqns = []
    for f in funcs:
        eq = diff(L, f)
        for i in range(1, order + 1):
            for p in combinations_with_replacement(vars, i):
                eq = eq + S.NegativeOne**i * diff(L, diff(f, *p), *p)
        eqns.append(Eq(eq))

    return eqns
Ejemplo n.º 24
0
def PolynomialRing(dom, *gens, **opts):
    r"""
    Create a generalized multivariate polynomial ring.

    A generalized polynomial ring is defined by a ground field `K`, a set
    of generators (typically `x_1, \ldots, x_n`) and a monomial order `<`.
    The monomial order can be global, local or mixed. In any case it induces
    a total ordering on the monomials, and there exists for every (non-zero)
    polynomial `f \in K[x_1, \ldots, x_n]` a well-defined "leading monomial"
    `LM(f) = LM(f, >)`. One can then define a multiplicative subset
    `S = S_> = \{f \in K[x_1, \ldots, x_n] | LM(f) = 1\}`. The generalized
    polynomial ring corresponding to the monomial order is
    `R = S^{-1}K[x_1, \ldots, x_n]`.

    If `>` is a so-called global order, that is `1` is the smallest monomial,
    then we just have `S = K` and `R = K[x_1, \ldots, x_n]`.

    Examples
    ========

    A few examples may make this clearer.

    >>> from diofant.abc import x, y
    >>> from diofant import QQ

    Our first ring uses global lexicographic order.

    >>> R1 = QQ.old_poly_ring(x, y, order=(("lex", x, y),))

    The second ring uses local lexicographic order. Note that when using a
    single (non-product) order, you can just specify the name and omit the
    variables:

    >>> R2 = QQ.old_poly_ring(x, y, order="ilex")

    The third and fourth rings use a mixed orders:

    >>> o1 = (("ilex", x), ("lex", y))
    >>> o2 = (("lex", x), ("ilex", y))
    >>> R3 = QQ.old_poly_ring(x, y, order=o1)
    >>> R4 = QQ.old_poly_ring(x, y, order=o2)

    We will investigate what elements of `K(x, y)` are contained in the various
    rings.

    >>> L = [x, 1/x, y/(1 + x), 1/(1 + y), 1/(1 + x*y)]
    >>> test = lambda R: [f in R for f in L]

    The first ring is just `K[x, y]`:

    >>> test(R1)
    [True, False, False, False, False]

    The second ring is R1 localised at the maximal ideal (x, y):

    >>> test(R2)
    [True, False, True, True, True]

    The third ring is R1 localised at the prime ideal (x):

    >>> test(R3)
    [True, False, True, False, True]

    Finally the fourth ring is R1 localised at `S = K[x, y] \setminus yK[y]`:

    >>> test(R4)
    [True, False, False, True, False]
    """

    order = opts.get("order", GeneralizedPolynomialRing.default_order)
    if iterable(order):
        order = build_product_order(order, gens)
    order = monomial_key(order)
    opts['order'] = order

    if order.is_global:
        return GlobalPolynomialRing(dom, *gens, **opts)
    else:
        return GeneralizedPolynomialRing(dom, *gens, **opts)
Ejemplo n.º 25
0
def test_iterable():
    assert iterable(0) is False
    assert iterable(1) is False
    assert iterable(None) is False
Ejemplo n.º 26
0
 def inv(l):
     if iterable(l):
         return tuple(inv(x) for x in l)
     return -l
Ejemplo n.º 27
0
def test_not_interable():
    i, j = symbols('i j', integer=True)
    A = Indexed('A', i, i + j)
    assert not iterable(A)
Ejemplo n.º 28
0
def test_iterable():
    assert iterable(0) is False
    assert iterable(1) is False
    assert iterable(None) is False