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
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))
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
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
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)
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])
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
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
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
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)
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)
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
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
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
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)
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
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