def __new__(cls, expr, *args, **kwargs): expr = sympify(expr) if not args: if expr.is_Order: variables = expr.variables point = expr.point else: variables = list(expr.free_symbols) point = [S.Zero] * len(variables) else: args = list(args if is_sequence(args) else [args]) variables, point = [], [] if is_sequence(args[0]): for a in args: v, p = list(map(sympify, a)) variables.append(v) point.append(p) else: variables = list(map(sympify, args)) point = [S.Zero] * len(variables) if not all(v.is_symbol for v in variables): raise TypeError('Variables are not symbols, got %s' % variables) if len(list(uniq(variables))) != len(variables): raise ValueError( 'Variables are supposed to be unique symbols, got %s' % variables) if expr.is_Order: expr_vp = dict(expr.args[1:]) new_vp = dict(expr_vp) vp = dict(zip(variables, point)) for v, p in vp.items(): if v in new_vp.keys(): if p != new_vp[v]: raise NotImplementedError( "Mixing Order at different points is not supported." ) else: new_vp[v] = p if set(expr_vp.keys()) == set(new_vp.keys()): return expr else: variables = list(new_vp.keys()) point = [new_vp[v] for v in variables] if expr is S.NaN: return S.NaN if any(x in p.free_symbols for x in variables for p in point): raise ValueError('Got %s as a point.' % point) if variables: if any(p != point[0] for p in point): raise NotImplementedError( "Multivariable orders at different points are not supported." ) if point[0] is S.Infinity: s = {k: 1 / Dummy() for k in variables} rs = {1 / v: 1 / k for k, v in s.items()} elif point[0] is S.NegativeInfinity: s = {k: -1 / Dummy() for k in variables} rs = {-1 / v: -1 / k for k, v in s.items()} elif point[0] is not S.Zero: s = dict((k, Dummy() + point[0]) for k in variables) rs = dict((v - point[0], k - point[0]) for k, v in s.items()) else: s = () rs = () expr = expr.subs(s) if expr.is_Add: from sympy import expand_multinomial expr = expand_multinomial(expr) if s: args = tuple([r[0] for r in rs.items()]) else: args = tuple(variables) if len(variables) > 1: # XXX: better way? We need this expand() to # workaround e.g: expr = x*(x + y). # (x*(x + y)).as_leading_term(x, y) currently returns # x*y (wrong order term!). That's why we want to deal with # expand()'ed expr (handled in "if expr.is_Add" branch below). expr = expr.expand() if expr.is_Add: lst = expr.extract_leading_order(args) expr = Add(*[f.expr for (e, f) in lst]) elif expr: expr = expr.as_leading_term(*args) expr = expr.as_independent(*args, as_Add=False)[1] expr = expand_power_base(expr) expr = expand_log(expr) if len(args) == 1: # The definition of O(f(x)) symbol explicitly stated that # the argument of f(x) is irrelevant. That's why we can # combine some power exponents (only "on top" of the # expression tree for f(x)), e.g.: # x**p * (-x)**q -> x**(p+q) for real p, q. x = args[0] margs = list( Mul.make_args(expr.as_independent(x, as_Add=False)[1])) for i, t in enumerate(margs): if t.is_Power: b, q = t.args if b in (x, -x) and q.is_real and not q.has(x): margs[i] = x**q elif b.is_Power and not b.exp.has(x): b, r = b.args if b in (x, -x) and r.is_real: margs[i] = x**(r * q) elif b.is_Mul and b.args[0] is S.NegativeOne: b = -b if b.is_Power and not b.exp.has(x): b, r = b.args if b in (x, -x) and r.is_real: margs[i] = x**(r * q) expr = Mul(*margs) expr = expr.subs(rs) if expr is S.Zero: return expr if expr.is_Order: expr = expr.expr if not expr.has(*variables): expr = S.One # create Order instance: vp = dict(zip(variables, point)) variables.sort(key=default_sort_key) point = [vp[v] for v in variables] args = (expr, ) + Tuple(*zip(variables, point)) obj = Expr.__new__(cls, *args) return obj
def __new__(cls, expr, *args, **kwargs): expr = sympify(expr) if not args: if expr.is_Order: variables = expr.variables point = expr.point else: variables = list(expr.free_symbols) point = [S.Zero]*len(variables) else: args = list(args if is_sequence(args) else [args]) variables, point = [], [] if is_sequence(args[0]): for a in args: v, p = list(map(sympify, a)) variables.append(v) point.append(p) else: variables = list(map(sympify, args)) point = [S.Zero]*len(variables) if not all(isinstance(v, Symbol) for v in variables): raise TypeError('Variables are not symbols, got %s' % variables) if len(list(uniq(variables))) != len(variables): raise ValueError('Variables are supposed to be unique symbols, got %s' % variables) if expr.is_Order: expr_vp = dict(expr.args[1:]) new_vp = dict(expr_vp) vp = dict(zip(variables, point)) for v, p in vp.items(): if v in new_vp.keys(): if p != new_vp[v]: raise NotImplementedError( "Mixing Order at different points is not supported.") else: new_vp[v] = p if set(expr_vp.keys()) == set(new_vp.keys()): return expr else: variables = list(new_vp.keys()) point = [new_vp[v] for v in variables] if expr is S.NaN: return S.NaN if not all(p is S.Zero for p in point) and \ not all(p is S.Infinity for p in point): raise NotImplementedError('Order at points other than 0 ' 'or oo not supported, got %s as a point.' % point) if variables: if len(variables) > 1: # XXX: better way? We need this expand() to # workaround e.g: expr = x*(x + y). # (x*(x + y)).as_leading_term(x, y) currently returns # x*y (wrong order term!). That's why we want to deal with # expand()'ed expr (handled in "if expr.is_Add" branch below). expr = expr.expand() if expr.is_Add: lst = expr.extract_leading_order(variables, point) expr = Add(*[f.expr for (e, f) in lst]) elif expr: if point[0] == S.Zero: expr = expr.as_leading_term(*variables) expr = expr.as_independent(*variables, as_Add=False)[1] expr = expand_power_base(expr) expr = expand_log(expr) if len(variables) == 1: # The definition of O(f(x)) symbol explicitly stated that # the argument of f(x) is irrelevant. That's why we can # combine some power exponents (only "on top" of the # expression tree for f(x)), e.g.: # x**p * (-x)**q -> x**(p+q) for real p, q. x = variables[0] margs = list(Mul.make_args( expr.as_independent(x, as_Add=False)[1])) for i, t in enumerate(margs): if t.is_Pow: b, q = t.args if b in (x, -x) and q.is_real and not q.has(x): margs[i] = x**q elif b.is_Pow and not b.exp.has(x): b, r = b.args if b in (x, -x) and r.is_real: margs[i] = x**(r*q) elif b.is_Mul and b.args[0] is S.NegativeOne: b = -b if b.is_Pow and not b.exp.has(x): b, r = b.args if b in (x, -x) and r.is_real: margs[i] = x**(r*q) expr = Mul(*margs) if expr is S.Zero: return expr if expr.is_Order: expr = expr.expr if not expr.has(*variables): expr = S.One # create Order instance: variables.sort(key=default_sort_key) args = (expr,) + Tuple(*zip(variables, point)) obj = Expr.__new__(cls, *args) return obj
def __new__(cls, expr, *symbols): expr = sympify(expr) if expr is S.NaN: return S.NaN point = S.Zero if symbols: symbols = list(map(sympify, symbols)) if symbols[-1] in (S.Infinity, S.Zero): point = symbols[-1] symbols = symbols[:-1] if not all(isinstance(s, Symbol) for s in symbols): raise NotImplementedError( 'Order at points other than 0 or oo not supported.') if not symbols: symbols = list(expr.free_symbols) if expr.is_Order: v = set(expr.variables) symbols = v | set(symbols) if symbols == v: return expr symbols = list(symbols) elif symbols: symbols = list(set(symbols)) args = tuple(symbols) + (point,) if len(symbols) > 1: # XXX: better way? We need this expand() to # workaround e.g: expr = x*(x + y). # (x*(x + y)).as_leading_term(x, y) currently returns # x*y (wrong order term!). That's why we want to deal with # expand()'ed expr (handled in "if expr.is_Add" branch below). expr = expr.expand() if expr.is_Add: lst = expr.extract_leading_order(*args) expr = Add(*[f.expr for (e, f) in lst]) elif expr: expr = expr.as_leading_term(*symbols) expr = expr.as_independent(*symbols, as_Add=False)[1] expr = expand_power_base(expr) expr = expand_log(expr) if len(symbols) == 1: # The definition of O(f(x)) symbol explicitly stated that # the argument of f(x) is irrelevant. That's why we can # combine some power exponents (only "on top" of the # expression tree for f(x)), e.g.: # x**p * (-x)**q -> x**(p+q) for real p, q. x = symbols[0] margs = list(Mul.make_args( expr.as_independent(x, as_Add=False)[1])) for i, t in enumerate(margs): if t.is_Pow: b, q = t.args if b in (x, -x) and q.is_real and not q.has(x): margs[i] = x**q elif b.is_Pow and not b.exp.has(x): b, r = b.args if b in (x, -x) and r.is_real: margs[i] = x**(r*q) elif b.is_Mul and b.args[0] is S.NegativeOne: b = -b if b.is_Pow and not b.exp.has(x): b, r = b.args if b in (x, -x) and r.is_real: margs[i] = x**(r*q) expr = Mul(*margs) if expr is S.Zero: return expr if not expr.has(*symbols): expr = S.One # create Order instance: symbols.sort(key=default_sort_key) args = (expr,) + tuple(symbols) + (point,) obj = Expr.__new__(cls, *args) return obj
def __new__(cls, expr, *symbols, **assumptions): expr = sympify(expr) if expr is S.NaN: return S.NaN if symbols: symbols = map(sympify, symbols) if not all(isinstance(s, Symbol) for s in symbols): raise NotImplementedError( 'Order at points other than 0 not supported.') else: symbols = list(expr.free_symbols) if expr.is_Order: v = set(expr.variables) symbols = v | set(symbols) if symbols == v: return expr symbols = list(symbols) elif symbols: symbols = list(set(symbols)) if len(symbols) > 1: # XXX: better way? We need this expand() to # workaround e.g: expr = x*(x + y). # (x*(x + y)).as_leading_term(x, y) currently returns # x*y (wrong order term!). That's why we want to deal with # expand()'ed expr (handled in "if expr.is_Add" branch below). expr = expr.expand() if expr.is_Add: lst = expr.extract_leading_order(*symbols) expr = Add(*[f.expr for (e, f) in lst]) elif expr: expr = expr.as_leading_term(*symbols) expr = expr.as_independent(*symbols, as_Add=False)[1] expr = expand_power_base(expr) expr = expand_log(expr) if len(symbols) == 1: # The definition of O(f(x)) symbol explicitly stated that # the argument of f(x) is irrelevant. That's why we can # combine some power exponents (only "on top" of the # expression tree for f(x)), e.g.: # x**p * (-x)**q -> x**(p+q) for real p, q. x = symbols[0] margs = list( Mul.make_args(expr.as_independent(x, as_Add=False)[1])) for i, t in enumerate(margs): if t.is_Pow: b, q = t.args if b in (x, -x) and q.is_real and not q.has(x): margs[i] = x**q elif b.is_Pow and not b.exp.has(x): b, r = b.args if b in (x, -x) and r.is_real: margs[i] = x**(r * q) elif b.is_Mul and b.args[0] is S.NegativeOne: b = -b if b.is_Pow and not b.exp.has(x): b, r = b.args if b in (x, -x) and r.is_real: margs[i] = x**(r * q) expr = Mul(*margs) if expr is S.Zero: return expr if not expr.has(*symbols): expr = S.One # create Order instance: symbols.sort(key=cmp_to_key(Basic.compare)) obj = Expr.__new__(cls, expr, *symbols, **assumptions) return obj
def __new__(cls, expr, *args, **kwargs): expr = sympify(expr) if not args: if expr.is_Order: variables = expr.variables point = expr.point else: variables = list(expr.free_symbols) point = [S.Zero]*len(variables) else: args = list(args if is_sequence(args) else [args]) variables, point = [], [] if is_sequence(args[0]): for a in args: v, p = list(map(sympify, a)) variables.append(v) point.append(p) else: variables = list(map(sympify, args)) point = [S.Zero]*len(variables) if not all(v.is_symbol for v in variables): raise TypeError('Variables are not symbols, got %s' % variables) if len(list(uniq(variables))) != len(variables): raise ValueError('Variables are supposed to be unique symbols, got %s' % variables) if expr.is_Order: expr_vp = dict(expr.args[1:]) new_vp = dict(expr_vp) vp = dict(zip(variables, point)) for v, p in vp.items(): if v in new_vp.keys(): if p != new_vp[v]: raise NotImplementedError( "Mixing Order at different points is not supported.") else: new_vp[v] = p if set(expr_vp.keys()) == set(new_vp.keys()): return expr else: variables = list(new_vp.keys()) point = [new_vp[v] for v in variables] if expr is S.NaN: return S.NaN if any(x in p.free_symbols for x in variables for p in point): raise ValueError('Got %s as a point.' % point) if variables: if any(p != point[0] for p in point): raise NotImplementedError( "Multivariable orders at different points are not supported.") if point[0] is S.Infinity: s = {k: 1/Dummy() for k in variables} rs = {1/v: 1/k for k, v in s.items()} ps = [S.Zero for p in point] elif point[0] is S.NegativeInfinity: s = {k: -1/Dummy() for k in variables} rs = {-1/v: -1/k for k, v in s.items()} ps = [S.Zero for p in point] elif point[0] is not S.Zero: s = {k: Dummy() + point[0] for k in variables} rs = {(v - point[0]).together(): k - point[0] for k, v in s.items()} ps = [S.Zero for p in point] else: s = () rs = () ps = list(point) expr = expr.subs(s) if expr.is_Add: expr = expr.factor() if s: args = tuple([r[0] for r in rs.items()]) else: args = tuple(variables) if len(variables) > 1: # XXX: better way? We need this expand() to # workaround e.g: expr = x*(x + y). # (x*(x + y)).as_leading_term(x, y) currently returns # x*y (wrong order term!). That's why we want to deal with # expand()'ed expr (handled in "if expr.is_Add" branch below). expr = expr.expand() old_expr = None while old_expr != expr: old_expr = expr if expr.is_Add: lst = expr.extract_leading_order(args) expr = Add(*[f.expr for (e, f) in lst]) elif expr: try: expr = expr.as_leading_term(*args) except PoleError: if isinstance(expr, Function) or\ all(isinstance(arg, Function) for arg in expr.args): # It is not possible to simplify an expression # containing only functions (which raise error on # call to leading term) further pass else: orders = [] pts = tuple(zip(args, ps)) for arg in expr.args: try: lt = arg.as_leading_term(*args) except PoleError: lt = arg if lt not in args: order = Order(lt) else: order = Order(lt, *pts) orders.append(order) if expr.is_Add: new_expr = Order(Add(*orders), *pts) if new_expr.is_Add: new_expr = Order(Add(*[a.expr for a in new_expr.args]), *pts) expr = new_expr.expr elif expr.is_Mul: expr = Mul(*[a.expr for a in orders]) elif expr.is_Pow: e = expr.exp b = expr.base expr = exp(e * log(b)) # It would probably be better to handle this somewhere # else. This is needed for a testcase in which there is a # symbol with the assumptions zero=True. if expr.is_zero: expr = S.Zero else: expr = expr.as_independent(*args, as_Add=False)[1] expr = expand_power_base(expr) expr = expand_log(expr) if len(args) == 1: # The definition of O(f(x)) symbol explicitly stated that # the argument of f(x) is irrelevant. That's why we can # combine some power exponents (only "on top" of the # expression tree for f(x)), e.g.: # x**p * (-x)**q -> x**(p+q) for real p, q. x = args[0] margs = list(Mul.make_args( expr.as_independent(x, as_Add=False)[1])) for i, t in enumerate(margs): if t.is_Pow: b, q = t.args if b in (x, -x) and q.is_real and not q.has(x): margs[i] = x**q elif b.is_Pow and not b.exp.has(x): b, r = b.args if b in (x, -x) and r.is_real: margs[i] = x**(r*q) elif b.is_Mul and b.args[0] is S.NegativeOne: b = -b if b.is_Pow and not b.exp.has(x): b, r = b.args if b in (x, -x) and r.is_real: margs[i] = x**(r*q) expr = Mul(*margs) expr = expr.subs(rs) if expr.is_Order: expr = expr.expr if not expr.has(*variables) and not expr.is_zero: expr = S.One # create Order instance: vp = dict(zip(variables, point)) variables.sort(key=default_sort_key) point = [vp[v] for v in variables] args = (expr,) + Tuple(*zip(variables, point)) obj = Expr.__new__(cls, *args) return obj
def __new__(cls, expr, *symbols, **assumptions): expr = sympify(expr).expand() if expr is S.NaN: return S.NaN if symbols: symbols = map(sympify, symbols) if not all(isinstance(s, Symbol) for s in symbols): raise NotImplementedError( 'Order at points other than 0 not supported.') else: symbols = list(expr.free_symbols) if expr.is_Order: v = set(expr.variables) symbols = v | set(symbols) if symbols == v: return expr symbols = list(symbols) elif symbols: symbols = list(set(symbols)) if expr.is_Add: lst = expr.extract_leading_order(*symbols) expr = Add(*[f.expr for (e, f) in lst]) elif expr: if len(symbols) > 1 or expr.is_commutative is False: # TODO # We cannot use compute_leading_term because that only # works in one symbol. expr = expr.as_leading_term(*symbols) else: expr = expr.compute_leading_term(symbols[0]) margs = list(Mul.make_args(expr.as_independent(*symbols)[1])) if len(symbols) == 1: # The definition of O(f(x)) symbol explicitly stated that # the argument of f(x) is irrelevant. That's why we can # combine some power exponents (only "on top" of the # expression tree for f(x)), e.g.: # x**p * (-x)**q -> x**(p+q) for real p, q. x = symbols[0] for i, t in enumerate(margs): if t.is_Pow: b, q = t.args if b in (x, -x) and q.is_real and not q.has(x): margs[i] = x**q elif b.is_Pow and not b.exp.has(x): b, r = b.args if b in (x, -x) and r.is_real: margs[i] = x**(r*q) elif b.is_Mul and b.args[0] is S.NegativeOne: b = -b if b.is_Pow and not b.exp.has(x): b, r = b.args if b in (x, -x) and r.is_real: margs[i] = x**(r*q) expr = Mul(*margs) if expr is S.Zero: return expr if not expr.has(*symbols): expr = S.One # create Order instance: symbols.sort(key=cmp_to_key(Basic.compare)) obj = Expr.__new__(cls, expr, *symbols, **assumptions) return obj