예제 #1
0
    def __new__(cls, function, *symbols, **assumptions):
        # Any embedded piecewise functions need to be brought out to the
        # top level so that integration can go into piecewise mode at the
        # earliest possible moment.
        function = piecewise_fold(sympify(function))

        if function.is_Number:
            if function is S.NaN:
                return S.NaN
            elif function is S.Infinity:
                return S.Infinity
            elif function is S.NegativeInfinity:
                return S.NegativeInfinity

        if symbols:
            limits = []

            for V in symbols:
                if isinstance(V, Symbol):
                    limits.append(Tuple(V))
                    continue
                elif isinstance(V, (tuple, list, Tuple)):
                    V = flatten(V)
                    newsymbol = sympify(V[0])
                    if len(V) == 3:
                        if isinstance(newsymbol, Symbol):
                            nlim = map(sympify, V[1:])
                            if V[1] is None and V[2] is not None:
                                nlim = [V[2]]
                            if V[2] is None and V[1] is not None:
                                function = -function
                                nlim = [V[1]]
                            if V[1] is None and V[2] is None:
                                nlim = []
                            limits.append( Tuple(newsymbol, *nlim ))
                            continue
                    elif len(V) == 1 or (len(V) == 2 and V[1] is None):
                        if isinstance(newsymbol, Symbol):
                            limits.append(Tuple(newsymbol))
                            continue
                    elif len(V) == 2:
                        if isinstance(newsymbol, Symbol):
                            limits.append(Tuple(newsymbol,V[1]))
                            continue


                raise ValueError("Invalid integration variable or limits: %s" % str(symbols))
        else:
            # no symbols provided -- let's compute full anti-derivative
            limits = [Tuple(symb) for symb in function.atoms(Symbol)]

            if not limits:
                return function

        obj = Expr.__new__(cls, **assumptions)
        arglist = [function]
        arglist.extend(limits)
        obj._args = tuple(arglist)

        return obj
예제 #2
0
파일: integrals.py 프로젝트: pyc111/sympy
 def _eval_expand_basic(self, deep=True, **hints):
     from sympy import flatten
     if not deep:
         return self
     else:
         return Integral(self.function.expand(deep=deep, **hints),\
         flatten(*self.limits))
예제 #3
0
def _process_limits(*symbols):
    """Process the list of symbols and convert them to canonical limits,
    storing them as Tuple(symbol, lower, upper). The orientation of
    the function is also returned when the upper limit is missing
    so (x, 1, None) becomes (x, None, 1) and the orientation is changed.
    """
    limits = []
    orientation = 1
    for V in symbols:
        if isinstance(V, (Relational, BooleanFunction)):
            variable = V.atoms(Symbol).pop()
            V = (variable, V.as_set())

        if isinstance(V, Symbol) or getattr(V, '_diff_wrt', False):
            if isinstance(V, Idx):
                if V.lower is None or V.upper is None:
                    limits.append(Tuple(V))
                else:
                    limits.append(Tuple(V, V.lower, V.upper))
            else:
                limits.append(Tuple(V))
            continue
        elif is_sequence(V, Tuple):
            V = sympify(flatten(V))
            if isinstance(V[0], (Symbol, Idx)) or getattr(V[0], '_diff_wrt', False):
                newsymbol = V[0]
                if len(V) == 2 and isinstance(V[1], Interval):
                    V[1:] = [V[1].start, V[1].end]

                if len(V) == 3:
                    if V[1] is None and V[2] is not None:
                        nlim = [V[2]]
                    elif V[1] is not None and V[2] is None:
                        orientation *= -1
                        nlim = [V[1]]
                    elif V[1] is None and V[2] is None:
                        nlim = []
                    else:
                        nlim = V[1:]
                    limits.append(Tuple(newsymbol, *nlim))
                    if isinstance(V[0], Idx):
                        if V[0].lower is not None and not bool(nlim[0] >= V[0].lower):
                            raise ValueError("Summation exceeds Idx lower range.")
                        if V[0].upper is not None and not bool(nlim[1] <= V[0].upper):
                            raise ValueError("Summation exceeds Idx upper range.")
                    continue
                elif len(V) == 1 or (len(V) == 2 and V[1] is None):
                    limits.append(Tuple(newsymbol))
                    continue
                elif len(V) == 2:
                    limits.append(Tuple(newsymbol, V[1]))
                    continue

        raise ValueError('Invalid limits given: %s' % str(symbols))

    return limits, orientation
예제 #4
0
파일: integrals.py 프로젝트: pyc111/sympy
    def __new__(cls, function, *symbols, **assumptions):
        # Any embedded piecewise functions need to be brought out to the
        # top level so that integration can go into piecewise mode at the
        # earliest possible moment.
        function = piecewise_fold(sympify(function))

        if function is S.NaN:
            return S.NaN

        symbols = list(symbols)
        if not symbols:
            # no symbols provided -- let's compute full anti-derivative
            symbols = sorted(function.free_symbols, Basic.compare)
            if not symbols:
                raise ValueError('An integration variable is required.')

        while isinstance(function, Integral):
            # denest the integrand
            symbols = list(function.limits) + symbols
            function = function.function

        limits = []
        for V in symbols:
            if isinstance(V, Symbol):
                limits.append(Tuple(V))
                continue
            elif isinstance(V, (tuple, list, Tuple)):
                V = sympify(flatten(V))
                if V[0].is_Symbol:
                    newsymbol = V[0]
                    if len(V) == 3:
                        if V[1] is None and V[2] is not None:
                            nlim = [V[2]]
                        elif V[1] is not None and V[2] is None:
                            function = -function
                            nlim = [V[1]]
                        elif V[1] is None and V[2] is None:
                            nlim = []
                        else:
                            nlim = V[1:]
                        limits.append(Tuple(newsymbol, *nlim ))
                        continue
                    elif len(V) == 1 or (len(V) == 2 and V[1] is None):
                        limits.append(Tuple(newsymbol))
                        continue
                    elif len(V) == 2:
                        limits.append(Tuple(newsymbol, V[1]))
                        continue
            raise ValueError("Invalid integration variable or limits: %s" % str(symbols))

        obj = Expr.__new__(cls, **assumptions)
        obj._args = tuple([function] + limits)
        obj.is_commutative = all(s.is_commutative for s in obj.free_symbols)

        return obj
예제 #5
0
파일: boolalg.py 프로젝트: cran/rSymPy
 def eval(cls, *args):
     out_args = []
     for arg in args: # we iterate over a copy or args
         if isinstance(arg, bool):
             if arg: return True
             else: continue
         out_args.append(arg)
     if len(out_args) == 0: return False
     if len(out_args) == 1: return out_args[0]
     sargs = sorted(flatten(out_args, cls=cls))
     return Basic.__new__(cls, *sargs)
예제 #6
0
파일: codegen.py 프로젝트: goriccardo/sympy
    def get_symbols(self):
        """Returns a set of all symbols related to this argument.

        Scalar arguments return themselves in a set, while array arguments return
        the array variable as well as all symbols the specifiy dimensions.
        """
        if self.dimensions:
            symbs = set(flatten(self.dimensions))
            symbs.add(self.name)
            return symbs
        else:
            return set([self.name])
예제 #7
0
    def __new__(cls, f, *symbols, **assumptions):
        f = sympify(f)

        if f.is_Number:
            if f is S.NaN:
                return S.NaN
            elif f is S.Zero:
                return S.Zero

        if not symbols:
            limits = f.atoms(Symbol)

            if not limits:
                return f
        else:
            limits = []

            for V in symbols:
                if isinstance(V, Symbol):
                    limits.append(Tuple(V))
                    continue
                elif isinstance(V, Equality):
                    if isinstance(V.lhs, Symbol):
                        if isinstance(V.rhs, Interval):
                            limits.append(Tuple(V.lhs, V.rhs.start, V.rhs.end))
                        else:
                            limits.append(Tuple(V.lhs, V.rhs))

                        continue
                elif isinstance(V, (tuple, list, Tuple)):
                    V = flatten(V)
                    if len(V) == 1:
                        if isinstance(V[0], Symbol):
                            limits.append(Tuple(V[0]))
                            continue
                    elif len(V) in (2, 3):
                        if isinstance(V[0], Symbol):
                            limits.append(Tuple(*map(sympify, V)))
                            continue

                raise ValueError("Invalid summation variable or limits")

        obj = Expr.__new__(cls, **assumptions)
        arglist = [f]
        arglist.extend(limits)
        obj._args = tuple(arglist)

        return obj
예제 #8
0
 def _getlogargs(expr):
     """
     Returns the arguments of the logarithm in an expression.
     Example:
     _getlogargs(a*log(x*y))
     x*y
     """
     if isinstance(expr, log):
         return [expr.args[0]]
     else:
         args = []
         for i in expr.args:
             if isinstance(i, log):
                 args.append(_getlogargs(i))
         return flatten(args)
     return None
예제 #9
0
def _process_limits(*symbols):
    """Convert the symbols-related limits into proper limits,
    storing them as Tuple(symbol, lower, upper). The sign of
    the function is also returned when the upper limit is missing
    so (x, 1, None) becomes (x, None, 1) and the sign is changed.
    """
    limits = []
    sign = 1
    for V in symbols:
        if isinstance(V, Symbol):
            limits.append(Tuple(V))
            continue
        elif is_sequence(V, Tuple):
            V = sympify(flatten(V))
            if V[0].is_Symbol:
                newsymbol = V[0]
                if len(V) == 2 and isinstance(V[1], Interval):
                    V[1:] = [V[1].start, V[1].end]

                if len(V) == 3:
                    if V[1] is None and V[2] is not None:
                        nlim = [V[2]]
                    elif V[1] is not None and V[2] is None:
                        sign *= -1
                        nlim = [V[1]]
                    elif V[1] is None and V[2] is None:
                        nlim = []
                    else:
                        nlim = V[1:]
                    limits.append(Tuple(newsymbol, *nlim ))
                    continue
                elif len(V) == 1 or (len(V) == 2 and V[1] is None):
                    limits.append(Tuple(newsymbol))
                    continue
                elif len(V) == 2:
                    limits.append(Tuple(newsymbol, V[1]))
                    continue

        raise ValueError('Invalid limits given: %s' % str(symbols))

    return limits, sign
예제 #10
0
def _separatevars(expr):
    # First try other expansion methods
    expr = expr.expand(mul=False, multinomial=False)
    try:
        expr = factor(expr)
    except PolynomialError:
        pass

    _coeff = Symbol('_coeff', dummy=True)

    if expr.is_Add:

        nonsepar = sympify(0)
        # Find any common coeficients to pull out
        commoncsetlist = []
        for i in expr.args:
            if i.is_Mul:
                commoncsetlist.append(set(i.args))
            else:
                commoncsetlist.append(set((i,)))
        commoncset = set(flatten(commoncsetlist))
        commonc = sympify(1)

        for i in commoncsetlist:
            commoncset = commoncset.intersection(i)
        commonc = Mul(*commoncset)

        for i in expr.args:
            coe = i.extract_multiplicatively(commonc)
            if coe == None:
                nonsepar += sympify(1)
            else:
                nonsepar += coe
        if nonsepar == 0:
            return commonc
        else:
            return commonc*nonsepar

    else:
        return expr
def smoothness_p(n, m=-1, power=0, visual=None):
    """Return a list of [m, (p, (M, sm(p + m), psm(p + m)))...]
    where:
        o p**M is the base-p divisor of n
        o sm(p + m) is the smoothness of p + m (m = -1 by default)
        o psm(p + n) is the power smoothness of p + m

    The list is sorted according to smoothness (default) or by power smoothness
    if power=1.

    The smoothness of the numbers to the left (m = -1) or right (m = 1) of a
    factor govern the results that are obtained from the p +/- 1 type factoring
    methods.

        >>> from sympy.ntheory.factor_ import smoothness_p, factorint
        >>> smoothness_p(10431, m=1)
        (1, [(3, (2, 2, 4)), (19, (1, 5, 5)), (61, (1, 31, 31))])
        >>> smoothness_p(10431)
        (-1, [(3, (2, 2, 2)), (19, (1, 3, 9)), (61, (1, 5, 5))])
        >>> smoothness_p(10431, power=1)
        (-1, [(3, (2, 2, 2)), (61, (1, 5, 5)), (19, (1, 3, 9))])

    If visual=True then an annotated string will be returned:

        >>> print smoothness_p(21477639576571, visual=1)
        p**i=4410317**1 has p-1 B=1787, B-pow=1787
        p**i=4869863**1 has p-1 B=2434931, B-pow=2434931

    This string can also be generated directly from a factorization dictionary
    and vice versa:

        >>> factorint(17*9)
        {3: 2, 17: 1}
        >>> smoothness_p(_)
        'p**i=3**2 has p-1 B=2, B-pow=2\\np**i=17**1 has p-1 B=2, B-pow=16'
        >>> smoothness_p(_)
        {3: 2, 17: 1}

    The table of the output logic is:

        _________________________________
        |       |        visual=        |
        | input + -----+--------+-------+
        |       | True | False  | other |
        +-------+------+--------+-------+
        | dict  | str  |  tuple | str   |
        | str   | str  |  tuple | dict  |
        | tuple | str  |  tuple | str   |
        | n     | str  |  tuple | tuple |
        | mul   | str  |  tuple | tuple |
        +-------+------+--------+-------+

        Note: recalculation of the input is done only for a Mul or dict, so
        smoothness_p({4: 2}, visual=False) == smoothness_p(16).

    """
    from sympy.utilities import flatten

    if type(n) is str:
        if visual:
            return n
        d = {}
        for li in n.splitlines():
            k, v = [int(i) for i in li.split("has")[0].split("=")[1].split("**")]
            d[k] = v
        if visual is not True and visual is not False:
            return d
        return smoothness_p(d, visual=False)
    elif type(n) is not tuple:
        facs = factorint(n, visual=False)

    if power:
        k = -1
    else:
        k = 1
    if type(n) is not tuple:
        rv = (
            m,
            sorted(
                [(f, tuple([M] + list(smoothness(f + m)))) for f, M in [i for i in facs.items()]],
                key=lambda x: (x[1][k], x[0]),
            ),
        )
    else:
        rv = n

    if visual is False or (visual != True) and (type(n) in [int, Mul]):
        return rv
    lines = []
    for dat in rv[1]:
        dat = flatten(dat)
        dat.insert(2, m)
        lines.append("p**i=%i**%i has p%+i B=%i, B-pow=%i" % tuple(dat))
    return "\n".join(lines)
예제 #12
0
def smoothness_p(n, m=-1, power=0, visual=None):
    """Return a list of [m, (p, (M, sm(p + m), psm(p + m)))...]
    where:
        o p**M is the base-p divisor of n
        o sm(p + m) is the smoothness of p + m (m = -1 by default)
        o psm(p + n) is the power smoothness of p + m

    The list is sorted according to smoothness (default) or by power smoothness
    if power=1.

    The smoothness of the numbers to the left (m = -1) or right (m = 1) of a
    factor govern the results that are obtained from the p +/- 1 type factoring
    methods.

        >>> from sympy.ntheory.factor_ import smoothness_p, factorint
        >>> smoothness_p(10431, m=1)
        (1, [(3, (2, 2, 4)), (19, (1, 5, 5)), (61, (1, 31, 31))])
        >>> smoothness_p(10431)
        (-1, [(3, (2, 2, 2)), (19, (1, 3, 9)), (61, (1, 5, 5))])
        >>> smoothness_p(10431, power=1)
        (-1, [(3, (2, 2, 2)), (61, (1, 5, 5)), (19, (1, 3, 9))])

    If visual=True then an annotated string will be returned:

        >>> print smoothness_p(21477639576571, visual=1)
        p**i=4410317**1 has p-1 B=1787, B-pow=1787
        p**i=4869863**1 has p-1 B=2434931, B-pow=2434931

    This string can also be generated directly from a factorization dictionary
    and vice versa:

        >>> factorint(17*9)
        {3: 2, 17: 1}
        >>> smoothness_p(_)
        'p**i=3**2 has p-1 B=2, B-pow=2\\np**i=17**1 has p-1 B=2, B-pow=16'
        >>> smoothness_p(_)
        {3: 2, 17: 1}

    The table of the output logic is:

        _________________________________
        |       |        visual=        |
        | input + -----+--------+-------+
        |       | True | False  | other |
        +-------+------+--------+-------+
        | dict  | str  |  tuple | str   |
        | str   | str  |  tuple | dict  |
        | tuple | str  |  tuple | str   |
        | n     | str  |  tuple | tuple |
        | mul   | str  |  tuple | tuple |
        +-------+------+--------+-------+

        Note: recalculation of the input is done only for a Mul or dict, so
        smoothness_p({4: 2}, visual=False) == smoothness_p(16).

    """
    from sympy.utilities import flatten

    if type(n) is str:
        if visual:
            return n
        d = {}
        for li in n.splitlines():
            k, v = [
                int(i) for i in li.split('has')[0].split('=')[1].split('**')
            ]
            d[k] = v
        if visual is not True and visual is not False:
            return d
        return smoothness_p(d, visual=False)
    elif type(n) is not tuple:
        facs = factorint(n, visual=False)

    if power:
        k = -1
    else:
        k = 1
    if type(n) is not tuple:
        rv = (m,
              sorted([(f, tuple([M] + list(smoothness(f + m))))
                      for f, M in [i for i in facs.items()]],
                     key=lambda x: (x[1][k], x[0])))
    else:
        rv = n

    if visual is False or (visual != True) and (type(n) in [int, Mul]):
        return rv
    lines = []
    for dat in rv[1]:
        dat = flatten(dat)
        dat.insert(2, m)
        lines.append('p**i=%i**%i has p%+i B=%i, B-pow=%i' % tuple(dat))
    return '\n'.join(lines)
예제 #13
0
 def _eval_adjoint(self):
     if all([x.is_real for x in flatten(self.limits)]):
         return self.func(self.function.adjoint(), *self.limits)
     return None
예제 #14
0
 def _eval_transpose(self):
     if all([x.is_real for x in flatten(self.limits)]):
         return self.func(self.function.transpose(), *self.limits)
     return None
예제 #15
0
 def _eval_conjugate(self):
     if all([x.is_real for x in flatten(self.limits)]):
         return self.func(self.function.conjugate(), *self.limits)
     return None
예제 #16
0
 def _eval_adjoint(self):
     if all([x.is_real for x in flatten(self.limits)]):
         return self.func(self.function.adjoint(), *self.limits)
     return None
예제 #17
0
파일: factor_.py 프로젝트: mattpap/sympy
def smoothness_p(n, m=-1, power=0, visual=None):
    """
    Return a list of [m, (p, (M, sm(p + m), psm(p + m)))...]
    where:

    1. p**M is the base-p divisor of n
    2. sm(p + m) is the smoothness of p + m (m = -1 by default)
    3. psm(p + n) is the power smoothness of p + m

    The list is sorted according to smoothness (default) or by power smoothness
    if power=1.

    The smoothness of the numbers to the left (m = -1) or right (m = 1) of a
    factor govern the results that are obtained from the p +/- 1 type factoring
    methods.

        >>> from sympy.ntheory.factor_ import smoothness_p, factorint
        >>> smoothness_p(10431, m=1)
        (1, [(3, (2, 2, 4)), (19, (1, 5, 5)), (61, (1, 31, 31))])
        >>> smoothness_p(10431)
        (-1, [(3, (2, 2, 2)), (19, (1, 3, 9)), (61, (1, 5, 5))])
        >>> smoothness_p(10431, power=1)
        (-1, [(3, (2, 2, 2)), (61, (1, 5, 5)), (19, (1, 3, 9))])

    If visual=True then an annotated string will be returned:

        >>> print smoothness_p(21477639576571, visual=1)
        p**i=4410317**1 has p-1 B=1787, B-pow=1787
        p**i=4869863**1 has p-1 B=2434931, B-pow=2434931

    This string can also be generated directly from a factorization dictionary
    and vice versa:

        >>> factorint(17*9)
        {3: 2, 17: 1}
        >>> smoothness_p(_)
        'p**i=3**2 has p-1 B=2, B-pow=2\\np**i=17**1 has p-1 B=2, B-pow=16'
        >>> smoothness_p(_)
        {3: 2, 17: 1}

    The table of the output logic is:

        ====== ====== ======= =======
        |              Visual
        ------ ----------------------
        Input  True   False   other
        ====== ====== ======= =======
        dict    str    tuple   str
        str     str    tuple   dict
        tuple   str    tuple   str
        n       str    tuple   tuple
        mul     str    tuple   tuple
        ====== ====== ======= =======

    See Also
    ========

    factorint, smoothness
    """
    from sympy.utilities import flatten

    # visual must be True, False or other (stored as None)
    if visual in (1, 0):
        visual = bool(visual)
    elif visual not in (True, False):
        visual = None

    if type(n) is str:
        if visual:
            return n
        d = {}
        for li in n.splitlines():
            k, v = [int(i) for i in
                    li.split('has')[0].split('=')[1].split('**')]
            d[k] = v
        if visual is not True and visual is not False:
            return d
        return smoothness_p(d, visual=False)
    elif type(n) is not tuple:
        facs = factorint(n, visual=False)

    if power:
        k = -1
    else:
        k = 1
    if type(n) is not tuple:
        rv = (m, sorted([(f,
                          tuple([M] + list(smoothness(f + m))))
                         for f, M in [i for i in facs.items()]],
                        key=lambda x: (x[1][k], x[0])))
    else:
        rv = n

    if visual is False or (visual is not True) and (type(n) in [int, Mul]):
        return rv
    lines = []
    for dat in rv[1]:
        dat = flatten(dat)
        dat.insert(2, m)
        lines.append('p**i=%i**%i has p%+i B=%i, B-pow=%i' % tuple(dat))
    return '\n'.join(lines)
예제 #18
0
 def _eval_conjugate(self):
     if all([x.is_real for x in flatten(self.limits)]):
         return self.func(self.function.conjugate(), *self.limits)
     return None
예제 #19
0
 def _eval_transpose(self):
     if all([x.is_real for x in flatten(self.limits)]):
         return self.func(self.function.transpose(), *self.limits)
     return None
예제 #20
0
def _process_limits(*symbols):
    """Process the list of symbols and convert them to canonical limits,
    storing them as Tuple(symbol, lower, upper). The orientation of
    the function is also returned when the upper limit is missing
    so (x, 1, None) becomes (x, None, 1) and the orientation is changed.
    """
    limits = []
    orientation = 1
    for V in symbols:
        if isinstance(V, (Relational, BooleanFunction)):
            variable = V.atoms(Symbol).pop()
            V = (variable, V.as_set())

        if isinstance(V, Symbol) or getattr(V, '_diff_wrt', False):
            if isinstance(V, Idx):
                if V.lower is None or V.upper is None:
                    limits.append(Tuple(V))
                else:
                    limits.append(Tuple(V, V.lower, V.upper))
            else:
                limits.append(Tuple(V))
            continue
        elif is_sequence(V, Tuple):
            if len(V) == 2 and isinstance(V[1], Range):
                lo = V[1].inf
                hi = V[1].sup
                dx = abs(V[1].step)
                V = [V[0]] + [0, (hi - lo) // dx, dx * V[0] + lo]
            V = sympify(flatten(V))  # a list of sympified elements
            if isinstance(V[0],
                          (Symbol, Idx)) or getattr(V[0], '_diff_wrt', False):
                newsymbol = V[0]
                if len(V) == 2 and isinstance(V[1], Interval):  # 2 -> 3
                    # Interval
                    V[1:] = [V[1].start, V[1].end]
                elif len(V) == 3:
                    # general case
                    if V[2] is None and not V[1] is None:
                        orientation *= -1
                    V = [newsymbol] + [i for i in V[1:] if i is not None]

                if not isinstance(newsymbol, Idx) or len(V) == 3:
                    if len(V) == 4:
                        limits.append(Tuple(*V))
                        continue
                    if len(V) == 3:
                        if isinstance(newsymbol, Idx):
                            # Idx represents an integer which may have
                            # specified values it can take on; if it is
                            # given such a value, an error is raised here
                            # if the summation would try to give it a larger
                            # or smaller value than permitted. None and Symbolic
                            # values will not raise an error.
                            lo, hi = newsymbol.lower, newsymbol.upper
                            try:
                                if lo is not None and not bool(V[1] >= lo):
                                    raise ValueError(
                                        "Summation will set Idx value too low."
                                    )
                            except TypeError:
                                pass
                            try:
                                if hi is not None and not bool(V[2] <= hi):
                                    raise ValueError(
                                        "Summation will set Idx value too high."
                                    )
                            except TypeError:
                                pass
                        limits.append(Tuple(*V))
                        continue
                    if len(V) == 1 or (len(V) == 2 and V[1] is None):
                        limits.append(Tuple(newsymbol))
                        continue
                    elif len(V) == 2:
                        limits.append(Tuple(newsymbol, V[1]))
                        continue

        raise ValueError('Invalid limits given: %s' % str(symbols))

    return limits, orientation
예제 #21
0
def _process_limits(*symbols):
    """Process the list of symbols and convert them to canonical limits,
    storing them as Tuple(symbol, lower, upper). The orientation of
    the function is also returned when the upper limit is missing
    so (x, 1, None) becomes (x, None, 1) and the orientation is changed.
    """
    limits = []
    orientation = 1
    for V in symbols:
        if isinstance(V, (Relational, BooleanFunction)):
            variable = V.atoms(Symbol).pop()
            V = (variable, V.as_set())

        if isinstance(V, Symbol) or getattr(V, '_diff_wrt', False):
            if isinstance(V, Idx):
                if V.lower is None or V.upper is None:
                    limits.append(Tuple(V))
                else:
                    limits.append(Tuple(V, V.lower, V.upper))
            else:
                limits.append(Tuple(V))
            continue
        elif is_sequence(V, Tuple):
            if len(V) == 2 and isinstance(V[1], Range):
                lo = V[1].inf
                hi = V[1].sup
                dx = abs(V[1].step)
                V = [V[0]] + [0, (hi - lo)//dx, dx*V[0] + lo]
            V = sympify(flatten(V))  # a list of sympified elements
            if isinstance(V[0], (Symbol, Idx)) or getattr(V[0], '_diff_wrt', False):
                newsymbol = V[0]
                if len(V) == 2 and isinstance(V[1], Interval):  # 2 -> 3
                    # Interval
                    V[1:] = [V[1].start, V[1].end]
                elif len(V) == 3:
                    # general case
                    if V[2] is None and not V[1] is None:
                        orientation *= -1
                    V = [newsymbol] + [i for i in V[1:] if i is not None]

                if not isinstance(newsymbol, Idx) or len(V) == 3:
                    if len(V) == 4:
                        limits.append(Tuple(*V))
                        continue
                    if len(V) == 3:
                        if isinstance(newsymbol, Idx):
                            # Idx represents an integer which may have
                            # specified values it can take on; if it is
                            # given such a value, an error is raised here
                            # if the summation would try to give it a larger
                            # or smaller value than permitted. None and Symbolic
                            # values will not raise an error.
                            lo, hi = newsymbol.lower, newsymbol.upper
                            try:
                                if lo is not None and not bool(V[1] >= lo):
                                    raise ValueError("Summation will set Idx value too low.")
                            except TypeError:
                                pass
                            try:
                                if hi is not None and not bool(V[2] <= hi):
                                    raise ValueError("Summation will set Idx value too high.")
                            except TypeError:
                                pass
                        limits.append(Tuple(*V))
                        continue
                    if len(V) == 1 or (len(V) == 2 and V[1] is None):
                        limits.append(Tuple(newsymbol))
                        continue
                    elif len(V) == 2:
                        limits.append(Tuple(newsymbol, V[1]))
                        continue

        raise ValueError('Invalid limits given: %s' % str(symbols))

    return limits, orientation