Skip to content

Module dewret.workflow

Overarching workflow concepts.

Basic constructs for describing a workflow.

Variables

LazyFactory
RetType
StepExecution
T
Target
U
logger

Functions

is_task

def is_task(
    task: 'Lazy'
) -> 'bool'

Decide whether this is a task.

Checks whether the wrapped function has the magic attribute __step_expression__ set to True, which is done within task creation.

Parameters:

Name Type Description Default
task None lazy-evaluated value, suspected to be a task. None

Returns:

Type Description
None True if task is indeed a task.

merge_workflows

def merge_workflows(
    *workflows: 'Workflow'
) -> 'Workflow'

Combine several workflows into one.

Merges a series of workflows by combining steps and tasks.

Argument: *workflows: series of workflows to combine.

Returns:

Type Description
None One workflow with all steps.

param

def param(
    name: 'str',
    default: 'T'
) -> 'T'

Create a parameter.

Will cast so it looks like the original type.

Returns:

Type Description
None Parameter class cast to the type of the supplied default.

Classes

Lazy

class Lazy(
    *args,
    **kwargs
)

Requirements for a lazy-evaluatable function.

Ancestors (in MRO)

  • typing.Protocol
  • typing.Generic

Descendants

  • dewret.workflow.LazyEvaluation

LazyEvaluation

class LazyEvaluation(
    fn: 'Callable[..., RetType]'
)

Tracks a single evaluation of a lazy function.

Ancestors (in MRO)

  • dewret.workflow.Lazy
  • typing.Protocol
  • typing.Generic

Parameter

class Parameter(
    name: 'str',
    default: 'T'
)

Global parameter.

Independent parameter that will be used when a task is spotted reaching outside its scope. This wraps the variable it uses.

To allow for potential arithmetic operations, etc. it is a Sympy symbol.

Attributes

Name Type Description Default
name None name of the parameter. None
default None captured default value from the original value. None

Ancestors (in MRO)

  • typing.Generic
  • sympy.core.symbol.Symbol
  • sympy.core.expr.AtomicExpr
  • sympy.core.basic.Atom
  • sympy.core.expr.Expr
  • sympy.logic.boolalg.Boolean
  • sympy.core.basic.Basic
  • sympy.printing.defaults.Printable
  • sympy.core.evalf.EvalfMixin

Class variables

default_assumptions
is_Add
is_AlgebraicNumber
is_Atom
is_Boolean
is_Derivative
is_Dummy
is_Equality
is_Float
is_Function
is_Indexed
is_Integer
is_MatAdd
is_MatMul
is_Matrix
is_Mul
is_Not
is_Number
is_NumberSymbol
is_Order
is_Piecewise
is_Point
is_Poly
is_Pow
is_Rational
is_Relational
is_Symbol
is_Vector
is_Wild
is_comparable
is_number
is_scalar
is_symbol
name

Static methods

class_key

def class_key(
    
)

Nice order of classes.

fromiter

def fromiter(
    args,
    **assumptions
)

Create a new object from an iterable.

This is a convenience function that allows one to create objects from any iterable, without having to convert to a list or tuple first.

Examples

from sympy import Tuple Tuple.fromiter(i for i in range(5)) (0, 1, 2, 3, 4)

Instance variables

args

Returns a tuple of arguments of 'self'.

Examples

from sympy import cot from sympy.abc import x, y

cot(x).args (x,)

cot(x).args[0] x

(x*y).args (x, y)

(x*y).args[1] y

Notes

Never use self._args, always use self.args. Only use _args in new when creating a new function. Do not override .args() from Basic (so that it is easy to change the interface in the future if needed).

assumptions0
binary_symbols
canonical_variables

Return a dictionary mapping any variable defined in

self.bound_symbols to Symbols that do not clash with any free symbols in the expression.

Examples

from sympy import Lambda from sympy.abc import x Lambda(x, 2*x).canonical_variables {x: _0}

expr_free_symbols
free_symbols
func

The top-level function in an expression.

The following should hold for all objects::

>> x == x.func(*x.args)

Examples

from sympy.abc import x a = 2x a.func a.args (2, x) a.func(a.args) 2x a == a.func(a.args) True

is_algebraic
is_antihermitian
is_commutative
is_complex
is_composite
is_even
is_extended_negative
is_extended_nonnegative
is_extended_nonpositive
is_extended_nonzero
is_extended_positive
is_extended_real
is_finite
is_hermitian
is_imaginary
is_infinite
is_integer
is_irrational
is_negative
is_noninteger
is_nonnegative
is_nonpositive
is_nonzero
is_odd
is_polar
is_positive
is_prime
is_rational
is_real
is_transcendental
is_zero
kind

Methods

adjoint

def adjoint(
    self
)

apart

def apart(
    self,
    x=None,
    **args
)

See the apart function in sympy.polys

args_cnc

def args_cnc(
    self,
    cset=False,
    warn=True,
    split_1=True
)

Return [commutative factors, non-commutative factors] of self.

Explanation

self is treated as a Mul and the ordering of the factors is maintained. If cset is True the commutative factors will be returned in a set. If there were repeated factors (as may happen with an unevaluated Mul) then an error will be raised unless it is explicitly suppressed by setting warn to False.

Note: -1 is always separated from a Number unless split_1 is False.

Examples

from sympy import symbols, oo A, B = symbols('A B', commutative=0) x, y = symbols('x y') (-2xy).args_cnc() [[-1, 2, x, y], []] (-2.5x).args_cnc() [[-1, 2.5, x], []] (-2xABy).args_cnc() [[-1, 2, x, y], [A, B]] (-2xABy).args_cnc(split_1=False) [[-2, x, y], [A, B]] (-2x*y).args_cnc(cset=True) [{-1, 2, x, y}, []]

The arg is always treated as a Mul:

(-2 + x + A).args_cnc() [[], [x - 2 + A]] (-oo).args_cnc() # -oo is a singleton [[-1, oo], []]

as_base_exp

def as_base_exp(
    self
) -> 'tuple[Expr, Expr]'

as_coeff_Add

def as_coeff_Add(
    self,
    rational=False
) -> "tuple['Number', Expr]"

Efficiently extract the coefficient of a summation.

as_coeff_Mul

def as_coeff_Mul(
    self,
    rational: 'bool' = False
) -> "tuple['Number', Expr]"

Efficiently extract the coefficient of a product.

as_coeff_add

def as_coeff_add(
    self,
    *deps
) -> 'tuple[Expr, tuple[Expr, ...]]'

Return the tuple (c, args) where self is written as an Add, a.

c should be a Rational added to any terms of the Add that are independent of deps.

args should be a tuple of all other terms of a; args is empty if self is a Number or if self is independent of deps (when given).

This should be used when you do not know if self is an Add or not but you want to treat self as an Add or if you want to process the individual arguments of the tail of self as an Add.

  • if you know self is an Add and want only the head, use self.args[0];
  • if you do not want to process the arguments of the tail but need the tail then use self.as_two_terms() which gives the head and tail.
  • if you want to split self into an independent and dependent parts use self.as_independent(*deps)

from sympy import S from sympy.abc import x, y (S(3)).as_coeff_add() (3, ()) (3 + x).as_coeff_add() (3, (x,)) (3 + x + y).as_coeff_add(x) (y + 3, (x,)) (3 + y).as_coeff_add(x) (y + 3, ())

as_coeff_exponent

def as_coeff_exponent(
    self,
    x
) -> 'tuple[Expr, Expr]'

c*x**e -> c,e where x can be any symbolic expression.

as_coeff_mul

def as_coeff_mul(
    self,
    *deps,
    **kwargs
) -> 'tuple[Expr, tuple[Expr, ...]]'

Return the tuple (c, args) where self is written as a Mul, m.

c should be a Rational multiplied by any factors of the Mul that are independent of deps.

args should be a tuple of all other factors of m; args is empty if self is a Number or if self is independent of deps (when given).

This should be used when you do not know if self is a Mul or not but you want to treat self as a Mul or if you want to process the individual arguments of the tail of self as a Mul.

  • if you know self is a Mul and want only the head, use self.args[0];
  • if you do not want to process the arguments of the tail but need the tail then use self.as_two_terms() which gives the head and tail;
  • if you want to split self into an independent and dependent parts use self.as_independent(*deps)

from sympy import S from sympy.abc import x, y (S(3)).as_coeff_mul() (3, ()) (3xy).as_coeff_mul() (3, (x, y)) (3xy).as_coeff_mul(x) (3y, (x,)) (3y).as_coeff_mul(x) (3*y, ())

as_coefficient

def as_coefficient(
    self,
    expr
)

Extracts symbolic coefficient at the given expression. In

other words, this functions separates 'self' into the product of 'expr' and 'expr'-free coefficient. If such separation is not possible it will return None.

Examples

from sympy import E, pi, sin, I, Poly from sympy.abc import x

E.as_coefficient(E) 1 (2E).as_coefficient(E) 2 (2sin(E)*E).as_coefficient(E)

Two terms have E in them so a sum is returned. (If one were desiring the coefficient of the term exactly matching E then the constant from the returned expression could be selected. Or, for greater precision, a method of Poly can be used to indicate the desired term from which the coefficient is desired.)

(2E + xE).as_coefficient(E) x + 2 _.args[0] # just want the exact match 2 p = Poly(2E + xE); p Poly(xE + 2E, x, E, domain='ZZ') p.coeff_monomial(E) 2 p.nth(0, 1) 2

Since the following cannot be written as a product containing E as a factor, None is returned. (If the coefficient 2*x is desired then the coeff method should be used.)

(2Ex + x).as_coefficient(E) (2Ex + x).coeff(E) 2*x

(E*(x + 1) + x).as_coefficient(E)

(2piI).as_coefficient(piI) 2 (2I).as_coefficient(pi*I)

See Also

coeff: return sum of terms have a given factor as_coeff_Add: separate the additive constant from an expression as_coeff_Mul: separate the multiplicative constant from an expression as_independent: separate x-dependent terms/factors from others sympy.polys.polytools.Poly.coeff_monomial: efficiently find the single coefficient of a monomial in Poly sympy.polys.polytools.Poly.nth: like coeff_monomial but powers of monomial terms are used

as_coefficients_dict

def as_coefficients_dict(
    self,
    *syms
)

Return a dictionary mapping terms to their Rational coefficient.

Since the dictionary is a defaultdict, inquiries about terms which were not present will return a coefficient of 0.

If symbols syms are provided, any multiplicative terms independent of them will be considered a coefficient and a regular dictionary of syms-dependent generators as keys and their corresponding coefficients as values will be returned.

Examples

from sympy.abc import a, x, y (3x + ax + 4).as_coefficients_dict() {1: 4, x: 3, ax: 1} _[a] 0 (3ax).as_coefficients_dict() {ax: 3} (3ax).as_coefficients_dict(x) {x: 3a} (3ax).as_coefficients_dict(y) {1: 3a*x}

as_content_primitive

def as_content_primitive(
    self,
    radical=False,
    clear=True
)

This method should recursively remove a Rational from all arguments

and return that (content) and the new self (primitive). The content should always be positive and Mul(*foo.as_content_primitive()) == foo. The primitive need not be in canonical form and should try to preserve the underlying structure if possible (i.e. expand_mul should not be applied to self).

Examples

from sympy import sqrt from sympy.abc import x, y, z

eq = 2 + 2x + 2y(3 + 3y)

The as_content_primitive function is recursive and retains structure:

eq.as_content_primitive() (2, x + 3y(y + 1) + 1)

Integer powers will have Rationals extracted from the base:

((2 + 6x)2).as_content_primitive() (4, (3x + 1)2) ((2 + 6*x)(2y)).as_content_primitive() (1, (2(3x + 1))(2y))

Terms may end up joining once their as_content_primitives are added:

((5(x(1 + y)) + 2x(3 + 3y))).as_content_primitive() (11, x(y + 1)) ((3(x(1 + y)) + 2x(3 + 3y))).as_content_primitive() (9, x(y + 1)) ((3(z(1 + y)) + 2.0x(3 + 3y))).as_content_primitive() (1, 6.0x(y + 1) + 3z(y + 1)) ((5(x(1 + y)) + 2x(3 + 3y))2).as_content_primitive() (121, x2(y + 1)2) ((x(1 + y) + 0.4x(3 + 3y))2).as_content_primitive() (1, 4.84x2*(y + 1)2)

Radical content can also be factored out of the primitive:

(2sqrt(2) + 4sqrt(10)).as_content_primitive(radical=True) (2, sqrt(2)(1 + 2sqrt(5)))

If clear=False (default is True) then content will not be removed from an Add if it can be distributed to leave one or more terms with integer coefficients.

(x/2 + y).as_content_primitive() (1/2, x + 2*y) (x/2 + y).as_content_primitive(clear=False) (1, x/2 + y)

as_dummy

def as_dummy(
    self
)

Return the expression with any objects having structurally

bound symbols replaced with unique, canonical symbols within the object in which they appear and having only the default assumption for commutativity being True. When applied to a symbol a new symbol having only the same commutativity will be returned.

Examples

from sympy import Integral, Symbol from sympy.abc import x r = Symbol('r', real=True) Integral(r, (r, x)).as_dummy() Integral(0, (_0, x)) .variables[0].is_real is None True r.as_dummy() _r

Notes

Any object that has structurally bound variables should have a property, bound_symbols that returns those symbols appearing in the object.

as_expr

def as_expr(
    self,
    *gens
)

Convert a polynomial to a SymPy expression.

Examples

from sympy import sin from sympy.abc import x, y

f = (x2 + x*y).as_poly(x, y) f.as_expr() x2 + x*y

sin(x).as_expr() sin(x)

as_independent

def as_independent(
    self,
    *deps,
    **hint
) -> 'tuple[Expr, Expr]'

A mostly naive separation of a Mul or Add into arguments that are not

are dependent on deps. To obtain as complete a separation of variables as possible, use a separation method first, e.g.:

  • separatevars() to change Mul, Add and Pow (including exp) into Mul
  • .expand(mul=True) to change Add or Mul into Add
  • .expand(log=True) to change log expr into an Add

The only non-naive thing that is done here is to respect noncommutative ordering of variables and to always return (0, 0) for self of zero regardless of hints.

For nonzero self, the returned tuple (i, d) has the following interpretation:

  • i will has no variable that appears in deps
  • d will either have terms that contain variables that are in deps, or be equal to 0 (when self is an Add) or 1 (when self is a Mul)
  • if self is an Add then self = i + d
  • if self is a Mul then self = i*d
  • otherwise (self, S.One) or (S.One, self) is returned.

To force the expression to be treated as an Add, use the hint as_Add=True

Examples

-- self is an Add

from sympy import sin, cos, exp from sympy.abc import x, y, z

(x + xy).as_independent(x) (0, xy + x) (x + xy).as_independent(y) (x, xy) (2xsin(x) + y + x + z).as_independent(x) (y + z, 2xsin(x) + x) (2xsin(x) + y + x + z).as_independent(x, y) (z, 2xsin(x) + x + y)

-- self is a Mul

(xsin(x)cos(y)).as_independent(x) (cos(y), x*sin(x))

non-commutative terms cannot always be separated out when self is a Mul

from sympy import symbols n1, n2, n3 = symbols('n1 n2 n3', commutative=False) (n1 + n1n2).as_independent(n2) (n1, n1n2) (n2n1 + n1n2).as_independent(n2) (0, n1n2 + n2n1) (n1n2n3).as_independent(n1) (1, n1n2n3) (n1n2n3).as_independent(n2) (n1, n2n3) ((x-n1)(x-y)).as_independent(x) (1, (x - y)*(x - n1))

-- self is anything else:

(sin(x)).as_independent(x) (1, sin(x)) (sin(x)).as_independent(y) (sin(x), 1) exp(x+y).as_independent(x) (1, exp(x + y))

-- force self to be treated as an Add:

(3x).as_independent(x, as_Add=True) (0, 3x)

-- force self to be treated as a Mul:

(3+x).as_independent(x, as_Add=False) (1, x + 3) (-3+x).as_independent(x, as_Add=False) (1, x - 3)

Note how the below differs from the above in making the constant on the dep term positive.

(y*(-3+x)).as_independent(x) (y, x - 3)

-- use .as_independent() for true independence testing instead of .has(). The former considers only symbols in the free symbols while the latter considers all symbols

from sympy import Integral I = Integral(x, (x, 1, 2)) I.has(x) True x in I.free_symbols False I.as_independent(x) == (I, 1) True (I + x).as_independent(x) == (I, x) True

Note: when trying to get independent terms, a separation method might need to be used first. In this case, it is important to keep track of what you send to this routine so you know how to interpret the returned values

from sympy import separatevars, log separatevars(exp(x+y)).as_independent(x) (exp(y), exp(x)) (x + xy).as_independent(y) (x, xy) separatevars(x + xy).as_independent(y) (x, y + 1) (x(1 + y)).as_independent(y) (x, y + 1) (x(1 + y)).expand(mul=True).as_independent(y) (x, xy) a, b=symbols('a b', positive=True) (log(a*b).expand(log=True)).as_independent(b) (log(a), log(b))

See Also

separatevars expand_log sympy.core.add.Add.as_two_terms sympy.core.mul.Mul.as_two_terms as_coeff_mul

as_leading_term

def as_leading_term(
    self,
    *symbols,
    logx=None,
    cdir=0
)

Returns the leading (nonzero) term of the series expansion of self.

The _eval_as_leading_term routines are used to do this, and they must always return a non-zero value.

Examples

from sympy.abc import x (1 + x + x2).as_leading_term(x) 1 (1/x2 + x + x2).as_leading_term(x) x(-2)

as_numer_denom

def as_numer_denom(
    self
)

Return the numerator and the denominator of an expression.

expression -> a/b -> a, b

This is just a stub that should be defined by an object's class methods to get anything else.

See Also

normal: return a/b instead of (a, b)

as_ordered_factors

def as_ordered_factors(
    self,
    order=None
)

Return list of ordered factors (if Mul) else [self].

as_ordered_terms

def as_ordered_terms(
    self,
    order=None,
    data=False
)

Transform an expression to an ordered list of terms.

Examples

from sympy import sin, cos from sympy.abc import x

(sin(x)2*cos(x) + sin(x)2 + 1).as_ordered_terms() [sin(x)2*cos(x), sin(x)2, 1]

as_poly

def as_poly(
    self,
    *gens,
    **args
)

Converts self to a polynomial or returns None.

Explanation

from sympy import sin from sympy.abc import x, y

print((x2 + x*y).as_poly()) Poly(x2 + x*y, x, y, domain='ZZ')

print((x2 + x*y).as_poly(x, y)) Poly(x2 + x*y, x, y, domain='ZZ')

print((x**2 + sin(y)).as_poly(x, y)) None

as_powers_dict

def as_powers_dict(
    self
)

Return self as a dictionary of factors with each factor being

treated as a power. The keys are the bases of the factors and the values, the corresponding exponents. The resulting dictionary should be used with caution if the expression is a Mul and contains non- commutative factors since the order that they appeared will be lost in the dictionary.

See Also

as_ordered_factors: An alternative for noncommutative applications, returning an ordered list of factors. args_cnc: Similar to as_ordered_factors, but guarantees separation of commutative and noncommutative factors.

as_real_imag

def as_real_imag(
    self,
    deep=True,
    **hints
)

Performs complex expansion on 'self' and returns a tuple

containing collected both real and imaginary parts. This method cannot be confused with re() and im() functions, which does not perform complex expansion at evaluation.

However it is possible to expand both re() and im() functions and get exactly the same results as with a single call to this function.

from sympy import symbols, I

x, y = symbols('x,y', real=True)

(x + y*I).as_real_imag() (x, y)

from sympy.abc import z, w

(z + w*I).as_real_imag() (re(z) - im(w), re(w) + im(z))

as_set

def as_set(
    self
)

Rewrites Boolean expression in terms of real sets.

Examples

from sympy import Symbol, Eq, Or, And x = Symbol('x', real=True) Eq(x, 0).as_set() {0} (x > 0).as_set() Interval.open(0, oo) And(-2 < x, x < 2).as_set() Interval.open(-2, 2) Or(x < -2, 2 < x).as_set() Union(Interval.open(-oo, -2), Interval.open(2, oo))

as_terms

def as_terms(
    self
)

Transform an expression to a list of terms.

aseries

def aseries(
    self,
    x=None,
    n=6,
    bound=0,
    hir=False
)

Asymptotic Series expansion of self.

This is equivalent to self.series(x, oo, n).

Parameters

self : Expression The expression whose series is to be expanded.

x : Symbol It is the variable of the expression to be calculated.

n : Value The value used to represent the order in terms of x**n, up to which the series is to be expanded.

hir : Boolean Set this parameter to be True to produce hierarchical series. It stops the recursion at an early level and may provide nicer and more useful results.

bound : Value, Integer Use the bound parameter to give limit on rewriting coefficients in its normalised form.

Examples

from sympy import sin, exp from sympy.abc import x

e = sin(1/x + exp(-x)) - sin(1/x)

e.aseries(x) (1/(24x4) - 1/(2x2) + 1 + O(x(-6), (x, oo)))*exp(-x)

e.aseries(x, n=3, hir=True) -exp(-2x)sin(1/x)/2 + exp(-x)cos(1/x) + O(exp(-3x), (x, oo))

e = exp(exp(x)/(1 - 1/x))

e.aseries(x) exp(exp(x)/(1 - 1/x))

e.aseries(x, bound=3) # doctest: +SKIP exp(exp(x)/x2)exp(exp(x)/x)exp(-exp(x) + exp(x)/(1 - 1/x) - exp(x)/x - exp(x)/x2)*exp(exp(x))

For rational expressions this method may return original expression without the Order term.

(1/x).aseries(x, n=8) 1/x

Returns

Expr Asymptotic series expansion of the expression.

Notes

This algorithm is directly induced from the limit computational algorithm provided by Gruntz. It majorly uses the mrv and rewrite sub-routines. The overall idea of this algorithm is first to look for the most rapidly varying subexpression w of a given expression f and then expands f in a series in w. Then same thing is recursively done on the leading coefficient till we get constant coefficients.

If the most rapidly varying subexpression of a given expression f is f itself, the algorithm tries to find a normalised representation of the mrv set and rewrites f using this normalised representation.

If the expansion contains an order term, it will be either O(x ** (-n)) or O(w ** (-n)) where w belongs to the most rapidly varying expression of self.

References

.. [1] Gruntz, Dominik. A new algorithm for computing asymptotic series. In: Proc. 1993 Int. Symp. Symbolic and Algebraic Computation. 1993. pp. 239-244. .. [2] Gruntz thesis - p90 .. [3] https://en.wikipedia.org/wiki/Asymptotic_expansion

See Also

Expr.aseries: See the docstring of this function for complete details of this wrapper.

atoms

def atoms(
    self,
    *types
)

Returns the atoms that form the current object.

By default, only objects that are truly atomic and cannot be divided into smaller pieces are returned: symbols, numbers, and number symbols like I and pi. It is possible to request atoms of any type, however, as demonstrated below.

Examples

from sympy import I, pi, sin from sympy.abc import x, y (1 + x + 2sin(y + Ipi)).atoms() {1, 2, I, pi, x, y}

If one or more types are given, the results will contain only those types of atoms.

from sympy import Number, NumberSymbol, Symbol (1 + x + 2sin(y + Ipi)).atoms(Symbol) {x, y}

(1 + x + 2sin(y + Ipi)).atoms(Number) {1, 2}

(1 + x + 2sin(y + Ipi)).atoms(Number, NumberSymbol) {1, 2, pi}

(1 + x + 2sin(y + Ipi)).atoms(Number, NumberSymbol, I) {1, 2, I, pi}

Note that I (imaginary unit) and zoo (complex infinity) are special types of number symbols and are not part of the NumberSymbol class.

The type can be given implicitly, too:

(1 + x + 2sin(y + Ipi)).atoms(x) # x is a Symbol {x, y}

Be careful to check your assumptions when using the implicit option since S(1).is_Integer = True but type(S(1)) is One, a special type of SymPy atom, while type(S(2)) is type Integer and will find all integers in an expression:

from sympy import S (1 + x + 2sin(y + Ipi)).atoms(S(1)) {1}

(1 + x + 2sin(y + Ipi)).atoms(S(2)) {1, 2}

Finally, arguments to atoms() can select more than atomic atoms: any SymPy type (loaded in core/init.py) can be listed as an argument and those types of "atoms" as found in scanning the arguments of the expression recursively:

from sympy import Function, Mul from sympy.core.function import AppliedUndef f = Function('f') (1 + f(x) + 2sin(y + Ipi)).atoms(Function) {f(x), sin(y + Ipi)} (1 + f(x) + 2sin(y + I*pi)).atoms(AppliedUndef) {f(x)}

(1 + x + 2sin(y + Ipi)).atoms(Mul) {Ipi, 2sin(y + I*pi)}

cancel

def cancel(
    self,
    *gens,
    **args
)

See the cancel function in sympy.polys

coeff

def coeff(
    self,
    x,
    n=1,
    right=False,
    _first=True
)

Returns the coefficient from the term(s) containing x**n. If n

is zero then all terms independent of x will be returned.

Explanation

When x is noncommutative, the coefficient to the left (default) or right of x can be returned. The keyword 'right' is ignored when x is commutative.

Examples

from sympy import symbols from sympy.abc import x, y, z

You can select terms that have an explicit negative in front of them:

(-x + 2y).coeff(-1) x (x - 2y).coeff(-1) 2*y

You can select terms with no Rational coefficient:

(x + 2y).coeff(1) x (3 + 2x + 4x*2).coeff(1) 0

You can select terms independent of x by making n=0; in this case expr.as_independent(x)[0] is returned (and 0 will be returned instead of None):

(3 + 2x + 4x2).coeff(x, 0) 3 eq = ((x + 1)3).expand() + 1 eq x3 + 3*x2 + 3*x + 2 [eq.coeff(x, i) for i in reversed(range(4))] [1, 3, 3, 2] eq -= 2 [eq.coeff(x, i) for i in reversed(range(4))] [1, 3, 3, 0]

You can select terms that have a numerical term in front of them:

(-x - 2y).coeff(2) -y from sympy import sqrt (x + sqrt(2)x).coeff(sqrt(2)) x

The matching is exact:

(3 + 2x + 4x2).coeff(x) 2 (3 + 2x + 4x2).coeff(x2) 4 (3 + 2x + 4x2).coeff(x3) 0 (z*(x + y)2).coeff((x + y)2) z (z*(x + y)2).coeff(x + y) 0

In addition, no factoring is done, so 1 + z*(1 + y) is not obtained from the following:

(x + z(x + xy)).coeff(x) 1

If such factoring is desired, factor_terms can be used first:

from sympy import factor_terms factor_terms(x + z(x + xy)).coeff(x) z*(y + 1) + 1

n, m, o = symbols('n m o', commutative=False) n.coeff(n) 1 (3n).coeff(n) 3 (nm + mnm).coeff(n) # = (1 + m)nm 1 + m (nm + mnm).coeff(n, right=True) # = (1 + m)n*m m

If there is more than one possible coefficient 0 is returned:

(nm + mn).coeff(n) 0

If there is only one possible coefficient, it is returned:

(nm + xmn).coeff(mn) x (nm + xmn).coeff(mn, right=1) 1

See Also

as_coefficient: separate the expression into a coefficient and factor as_coeff_Add: separate the additive constant from an expression as_coeff_Mul: separate the multiplicative constant from an expression as_independent: separate x-dependent terms/factors from others sympy.polys.polytools.Poly.coeff_monomial: efficiently find the single coefficient of a monomial in Poly sympy.polys.polytools.Poly.nth: like coeff_monomial but powers of monomial terms are used

collect

def collect(
    self,
    syms,
    func=None,
    evaluate=True,
    exact=False,
    distribute_order_term=True
)

See the collect function in sympy.simplify

combsimp

def combsimp(
    self
)

See the combsimp function in sympy.simplify

compare

def compare(
    self,
    other
)

Return -1, 0, 1 if the object is smaller, equal, or greater than other.

Not in the mathematical sense. If the object is of a different type from the "other" then their classes are ordered according to the sorted_classes list.

Examples

from sympy.abc import x, y x.compare(y) -1 x.compare(x) 0 y.compare(x) 1

compute_leading_term

def compute_leading_term(
    self,
    x,
    logx=None
)

Deprecated function to compute the leading term of a series.

as_leading_term is only allowed for results of .series() This is a wrapper to compute a series first.

conjugate

def conjugate(
    self
)

Returns the complex conjugate of 'self'.

copy

def copy(
    self
)

could_extract_minus_sign

def could_extract_minus_sign(
    self
)

Return True if self has -1 as a leading factor or has

more literal negative signs than positive signs in a sum, otherwise False.

Examples

from sympy.abc import x, y e = x - y {i.could_extract_minus_sign() for i in (e, -e)} {False, True}

Though the y - x is considered like -(x - y), since it is in a product without a leading factor of -1, the result is false below:

(x*(y - x)).could_extract_minus_sign() False

To put something in canonical form wrt to sign, use signsimp:

from sympy import signsimp signsimp(x(y - x)) -x(x - y) _.could_extract_minus_sign() True

count

def count(
    self,
    query
)

Count the number of matching subexpressions.

count_ops

def count_ops(
    self,
    visual=None
)

Wrapper for count_ops that returns the operation count.

diff

def diff(
    self,
    *symbols,
    **assumptions
)

dir

def dir(
    self,
    x,
    cdir
)

doit

def doit(
    self,
    **hints
)

Evaluate objects that are not evaluated by default like limits,

integrals, sums and products. All objects of this kind will be evaluated recursively, unless some species were excluded via 'hints' or unless the 'deep' hint was set to 'False'.

from sympy import Integral from sympy.abc import x

2Integral(x, x) 2Integral(x, x)

(2Integral(x, x)).doit() x*2

(2Integral(x, x)).doit(deep=False) 2Integral(x, x)

dummy_eq

def dummy_eq(
    self,
    other,
    symbol=None
)

Compare two expressions and handle dummy symbols.

Examples

from sympy import Dummy from sympy.abc import x, y

u = Dummy('u')

(u2 + 1).dummy_eq(x2 + 1) True (u2 + 1) == (x2 + 1) False

(u2 + y).dummy_eq(x2 + y, x) True (u2 + y).dummy_eq(x2 + y, y) False

equals

def equals(
    self,
    other,
    failing_expression=False
)

Return True if self == other, False if it does not, or None. If

failing_expression is True then the expression which did not simplify to a 0 will be returned instead of None.

Explanation

If self is a Number (or complex number) that is not zero, then the result is False.

If self is a number and has not evaluated to zero, evalf will be used to test whether the expression evaluates to zero. If it does so and the result has significance (i.e. the precision is either -1, for a Rational result, or is greater than 1) then the evalf value will be used to return True or False.

evalf

def evalf(
    self,
    n=15,
    subs=None,
    maxn=100,
    chop=False,
    strict=False,
    quad=None,
    verbose=False
)

Evaluate the given formula to an accuracy of n digits.

Parameters

subs : dict, optional Substitute numerical values for symbols, e.g. subs={x:3, y:1+pi}. The substitutions must be given as a dictionary.

maxn : int, optional Allow a maximum temporary working precision of maxn digits.

chop : bool or number, optional Specifies how to replace tiny real or imaginary parts in subresults by exact zeros.

When ``True`` the chop value defaults to standard precision.

Otherwise the chop value is used to determine the
magnitude of "small" for purposes of chopping.

>>> from sympy import N
>>> x = 1e-4
>>> N(x, chop=True)
0.000100000000000000
>>> N(x, chop=1e-5)
0.000100000000000000
>>> N(x, chop=1e-4)
0

strict : bool, optional Raise PrecisionExhausted if any subresult fails to evaluate to full accuracy, given the available maxprec.

quad : str, optional Choose algorithm for numerical quadrature. By default, tanh-sinh quadrature is used. For oscillatory integrals on an infinite interval, try quad='osc'.

verbose : bool, optional Print debug information.

Notes

When Floats are naively substituted into an expression, precision errors may adversely affect the result. For example, adding 1e16 (a Float) to 1 will truncate to 1e16; if 1e16 is then subtracted, the result will be 0. That is exactly what happens in the following:

from sympy.abc import x, y, z values = {x: 1e16, y: 1, z: 1e16} (x + y - z).subs(values) 0

Using the subs argument for evalf is the accurate way to evaluate such an expression:

(x + y - z).evalf(subs=values) 1.00000000000000

expand

def expand(
    self,
    deep=True,
    modulus=None,
    power_base=True,
    power_exp=True,
    mul=True,
    log=True,
    multinomial=True,
    basic=True,
    **hints
)

Expand an expression using hints.

See the docstring of the expand() function in sympy.core.function for more information.

extract_additively

def extract_additively(
    self,
    c
)

Return self - c if it's possible to subtract c from self and

make all matching coefficients move towards zero, else return None.

Examples

from sympy.abc import x, y e = 2x + 3 e.extract_additively(x + 1) x + 2 e.extract_additively(3x) e.extract_additively(4) (y(x + 1)).extract_additively(x + 1) ((x + 1)(x + 2y + 1) + 3).extract_additively(x + 1) (x + 1)(x + 2*y) + 3

See Also

extract_multiplicatively coeff as_coefficient

extract_branch_factor

def extract_branch_factor(
    self,
    allow_half=False
)

Try to write self as exp_polar(2*pi*I*n)*z in a nice way.

Return (z, n).

from sympy import exp_polar, I, pi from sympy.abc import x, y exp_polar(Ipi).extract_branch_factor() (exp_polar(Ipi), 0) exp_polar(2Ipi).extract_branch_factor() (1, 1) exp_polar(-piI).extract_branch_factor() (exp_polar(Ipi), -1) exp_polar(3piI + x).extract_branch_factor() (exp_polar(x + Ipi), 1) (yexp_polar(-5piI)exp_polar(3piI + 2pix)).extract_branch_factor() (yexp_polar(2pix), -1) exp_polar(-Ipi/2).extract_branch_factor() (exp_polar(-Ipi/2), 0)

If allow_half is True, also extract exp_polar(I*pi):

exp_polar(Ipi).extract_branch_factor(allow_half=True) (1, 1/2) exp_polar(2Ipi).extract_branch_factor(allow_half=True) (1, 1) exp_polar(3Ipi).extract_branch_factor(allow_half=True) (1, 3/2) exp_polar(-Ipi).extract_branch_factor(allow_half=True) (1, -1/2)

extract_multiplicatively

def extract_multiplicatively(
    self,
    c
)

Return None if it's not possible to make self in the form

c * something in a nice way, i.e. preserving the properties of arguments of self.

Examples

from sympy import symbols, Rational

x, y = symbols('x,y', real=True)

((xy)3).extract_multiplicatively(x2 * y) xy**2

((xy)3).extract_multiplicatively(x*4 * y)

(2*x).extract_multiplicatively(2) x

(2*x).extract_multiplicatively(3)

(Rational(1, 2)*x).extract_multiplicatively(3) x/6

factor

def factor(
    self,
    *gens,
    **args
)

See the factor() function in sympy.polys.polytools

find

def find(
    self,
    query,
    group=False
)

Find all subexpressions matching a query.

fourier_series

def fourier_series(
    self,
    limits=None
)

Compute fourier sine/cosine series of self.

See the docstring of the :func:fourier_series in sympy.series.fourier for more information.

fps

def fps(
    self,
    x=None,
    x0=0,
    dir=1,
    hyper=True,
    order=4,
    rational=True,
    full=False
)

Compute formal power power series of self.

See the docstring of the :func:fps function in sympy.series.formal for more information.

gammasimp

def gammasimp(
    self
)

See the gammasimp function in sympy.simplify

getO

def getO(
    self
)

Returns the additive O(..) symbol if there is one, else None.

getn

def getn(
    self
)

Returns the order of the expression.

Explanation

The order is determined either from the O(...) term. If there is no O(...) term, it returns None.

Examples

from sympy import O from sympy.abc import x (1 + x + O(x**2)).getn() 2 (1 + x).getn()

has

def has(
    self,
    *patterns
)

Test whether any subexpression matches any of the patterns.

Examples

from sympy import sin from sympy.abc import x, y, z (x2 + sin(x*y)).has(z) False (x2 + sin(x*y)).has(x, y, z) True x.has(x) True

Note has is a structural algorithm with no knowledge of mathematics. Consider the following half-open interval:

from sympy import Interval i = Interval.Lopen(0, 5); i Interval.Lopen(0, 5) i.args (0, 5, True, False) i.has(4) # there is no "4" in the arguments False i.has(0) # there is a "0" in the arguments True

Instead, use contains to determine whether a number is in the interval or not:

i.contains(4) True i.contains(0) False

Note that expr.has(*patterns) is exactly equivalent to any(expr.has(p) for p in patterns). In particular, False is returned when the list of patterns is empty.

x.has() False

has_free

def has_free(
    self,
    *patterns
)

Return True if self has object(s) x as a free expression

else False.

Examples

from sympy import Integral, Function from sympy.abc import x, y f = Function('f') g = Function('g') expr = Integral(f(x), (f(x), 1, g(y))) expr.free_symbols {y} expr.has_free(g(y)) True expr.has_free(*(x, f(x))) False

This works for subexpressions and types, too:

expr.has_free(g) True (x + y + 1).has_free(y + 1) True

has_xfree

def has_xfree(
    self,
    s: 'set[Basic]'
)

Return True if self has any of the patterns in s as a

free argument, else False. This is like Basic.has_free but this will only report exact argument matches.

Examples

from sympy import Function from sympy.abc import x, y f = Function('f') f(x).has_xfree({f}) False f(x).has_xfree({f(x)}) True f(x + 1).has_xfree({x}) True f(x + 1).has_xfree({x + 1}) True f(x + y + 1).has_xfree({x + 1}) False

integrate

def integrate(
    self,
    *args,
    **kwargs
)

See the integrate function in sympy.integrals

invert

def invert(
    self,
    g,
    *gens,
    **args
)

Return the multiplicative inverse of self mod g

where self (and g) may be symbolic expressions).

See Also

sympy.core.numbers.mod_inverse, sympy.polys.polytools.invert

is_algebraic_expr

def is_algebraic_expr(
    self,
    *syms
)

This tests whether a given expression is algebraic or not, in the

given symbols, syms. When syms is not given, all free symbols will be used. The rational function does not have to be in expanded or in any kind of canonical form.

This function returns False for expressions that are "algebraic expressions" with symbolic exponents. This is a simple extension to the is_rational_function, including rational exponentiation.

Examples

from sympy import Symbol, sqrt x = Symbol('x', real=True) sqrt(1 + x).is_rational_function() False sqrt(1 + x).is_algebraic_expr() True

This function does not attempt any nontrivial simplifications that may result in an expression that does not appear to be an algebraic expression to become one.

from sympy import exp, factor a = sqrt(exp(x)*2 + 2exp(x) + 1)/(exp(x) + 1) a.is_algebraic_expr(x) False factor(a).is_algebraic_expr() True

See Also

is_rational_function

References

.. [1] https://en.wikipedia.org/wiki/Algebraic_expression

is_constant

def is_constant(
    self,
    *wrt,
    **flags
)

Return True if self is constant, False if not, or None if

the constancy could not be determined conclusively.

Explanation

If an expression has no free symbols then it is a constant. If there are free symbols it is possible that the expression is a constant, perhaps (but not necessarily) zero. To test such expressions, a few strategies are tried:

1) numerical evaluation at two random points. If two such evaluations give two different values and the values have a precision greater than 1 then self is not constant. If the evaluations agree or could not be obtained with any precision, no decision is made. The numerical testing is done only if wrt is different than the free symbols.

2) differentiation with respect to variables in 'wrt' (or all free symbols if omitted) to see if the expression is constant or not. This will not always lead to an expression that is zero even though an expression is constant (see added test in test_expr.py). If all derivatives are zero then self is constant with respect to the given symbols.

3) finding out zeros of denominator expression with free_symbols. It will not be constant if there are zeros. It gives more negative answers for expression that are not constant.

If neither evaluation nor differentiation can prove the expression is constant, None is returned unless two numerical values happened to be the same and the flag failing_number is True -- in that case the numerical value will be returned.

If flag simplify=False is passed, self will not be simplified; the default is True since self should be simplified before testing.

Examples

from sympy import cos, sin, Sum, S, pi from sympy.abc import a, n, x, y x.is_constant() False S(2).is_constant() True Sum(x, (x, 1, 10)).is_constant() True Sum(x, (x, 1, n)).is_constant() False Sum(x, (x, 1, n)).is_constant(y) True Sum(x, (x, 1, n)).is_constant(n) False Sum(x, (x, 1, n)).is_constant(x) True eq = acos(x)2 + asin(x)**2 - a eq.is_constant() True eq.subs({x: pi, a: 2}) == eq.subs({x: pi, a: 3}) == 0 True

(0x).is_constant() False x.is_constant() False (xx).is_constant() False one = cos(x)2 + sin(x)2 one.is_constant() True ((one - 1)**(x + 1)).is_constant() in (True, False) # could be 0 or 1 True

is_hypergeometric

def is_hypergeometric(
    self,
    k
)

is_meromorphic

def is_meromorphic(
    self,
    x,
    a
)

This tests whether an expression is meromorphic as

a function of the given symbol x at the point a.

This method is intended as a quick test that will return None if no decision can be made without simplification or more detailed analysis.

Examples

from sympy import zoo, log, sin, sqrt from sympy.abc import x

f = 1/x2 + 1 - 2*x3 f.is_meromorphic(x, 0) True f.is_meromorphic(x, 1) True f.is_meromorphic(x, zoo) True

g = x**log(3) g.is_meromorphic(x, 0) False g.is_meromorphic(x, 1) True g.is_meromorphic(x, zoo) False

h = sin(1/x)x*2 h.is_meromorphic(x, 0) False h.is_meromorphic(x, 1) True h.is_meromorphic(x, zoo) True

Multivalued functions are considered meromorphic when their branches are meromorphic. Thus most functions are meromorphic everywhere except at essential singularities and branch points. In particular, they will be meromorphic also on branch cuts except at their endpoints.

log(x).is_meromorphic(x, -1) True log(x).is_meromorphic(x, 0) False sqrt(x).is_meromorphic(x, -1) True sqrt(x).is_meromorphic(x, 0) False

is_polynomial

def is_polynomial(
    self,
    *syms
)

Return True if self is a polynomial in syms and False otherwise.

This checks if self is an exact polynomial in syms. This function returns False for expressions that are "polynomials" with symbolic exponents. Thus, you should be able to apply polynomial algorithms to expressions for which this returns True, and Poly(expr, *syms) should work if and only if expr.is_polynomial(*syms) returns True. The polynomial does not have to be in expanded form. If no symbols are given, all free symbols in the expression will be used.

This is not part of the assumptions system. You cannot do Symbol('z', polynomial=True).

Examples

from sympy import Symbol, Function x = Symbol('x') ((x2 + 1)4).is_polynomial(x) True ((x2 + 1)4).is_polynomial() True (2x + 1).is_polynomial(x) False (2x + 1).is_polynomial(2**x) True f = Function('f') (f(x) + 1).is_polynomial(x) False (f(x) + 1).is_polynomial(f(x)) True (1/f(x) + 1).is_polynomial(f(x)) False

n = Symbol('n', nonnegative=True, integer=True) (x**n + 1).is_polynomial(x) False

This function does not attempt any nontrivial simplifications that may result in an expression that does not appear to be a polynomial to become one.

from sympy import sqrt, factor, cancel y = Symbol('y', positive=True) a = sqrt(y*2 + 2y + 1) a.is_polynomial(y) False factor(a) y + 1 factor(a).is_polynomial(y) True

b = (y*2 + 2y + 1)/(y + 1) b.is_polynomial(y) False cancel(b) y + 1 cancel(b).is_polynomial(y) True

See also .is_rational_function()

is_rational_function

def is_rational_function(
    self,
    *syms
)

Test whether function is a ratio of two polynomials in the given

symbols, syms. When syms is not given, all free symbols will be used. The rational function does not have to be in expanded or in any kind of canonical form.

This function returns False for expressions that are "rational functions" with symbolic exponents. Thus, you should be able to call .as_numer_denom() and apply polynomial algorithms to the result for expressions for which this returns True.

This is not part of the assumptions system. You cannot do Symbol('z', rational_function=True).

Examples

from sympy import Symbol, sin from sympy.abc import x, y

(x/y).is_rational_function() True

(x**2).is_rational_function() True

(x/sin(y)).is_rational_function(y) False

n = Symbol('n', integer=True) (x**n + 1).is_rational_function(x) False

This function does not attempt any nontrivial simplifications that may result in an expression that does not appear to be a rational function to become one.

from sympy import sqrt, factor y = Symbol('y', positive=True) a = sqrt(y*2 + 2y + 1)/y a.is_rational_function(y) False factor(a) (y + 1)/y factor(a).is_rational_function(y) True

See also is_algebraic_expr().

leadterm

def leadterm(
    self,
    x,
    logx=None,
    cdir=0
)

Returns the leading term ax*b as a tuple (a, b).

Examples

from sympy.abc import x (1+x+x2).leadterm(x) (1, 0) (1/x2+x+x**2).leadterm(x) (1, -2)

limit

def limit(
    self,
    x,
    xlim,
    dir='+'
)

Compute limit x->xlim.

lseries

def lseries(
    self,
    x=None,
    x0=0,
    dir='+',
    logx=None,
    cdir=0
)

Wrapper for series yielding an iterator of the terms of the series.

Note: an infinite series will yield an infinite iterator. The following, for exaxmple, will never terminate. It will just keep printing terms of the sin(x) series::

for term in sin(x).lseries(x): print term

The advantage of lseries() over nseries() is that many times you are just interested in the next term in the series (i.e. the first term for example), but you do not know how many you should ask for in nseries() using the "n" parameter.

See also nseries().

match

def match(
    self,
    pattern,
    old=False
)

Pattern matching.

Wild symbols match all.

Return None when expression (self) does not match with pattern. Otherwise return a dictionary such that::

pattern.xreplace(self.match(pattern)) == self

Examples

from sympy import Wild, Sum from sympy.abc import x, y p = Wild("p") q = Wild("q") r = Wild("r") e = (x+y)(x+y) e.match(pp) {p_: x + y} e.match(pq) {p_: x + y, q_: x + y} e = (2*x)2 e.match(pqr) {p_: 4, q_: x, r_: 2} (pqr).xreplace(e.match(p*qr)) 4x*2

Structurally bound symbols are ignored during matching:

Sum(x, (x, 1, 2)).match(Sum(y, (y, 1, p))) {p_: 2}

But they can be identified if desired:

Sum(x, (x, 1, 2)).match(Sum(q, (q, 1, p))) {p_: 2, q_: x}

The old flag will give the old-style pattern matching where expressions and patterns are essentially solved to give the match. Both of the following give None unless old=True:

(x - 2).match(p - x, old=True) {p_: 2x - 2} (2/x).match(px, old=True) {p_: 2/x**2}

matches

def matches(
    self,
    expr,
    repl_dict=None,
    old=False
)

Helper method for match() that looks for a match between Wild symbols

in self and expressions in expr.

Examples

from sympy import symbols, Wild, Basic a, b, c = symbols('a b c') x = Wild('x') Basic(a + x, x).matches(Basic(a + b, c)) is None True Basic(a + x, x).matches(Basic(a + b + c, b + c)) {x_: b + c}

n

def n(
    self,
    n=15,
    subs=None,
    maxn=100,
    chop=False,
    strict=False,
    quad=None,
    verbose=False
)

Evaluate the given formula to an accuracy of n digits.

Parameters

subs : dict, optional Substitute numerical values for symbols, e.g. subs={x:3, y:1+pi}. The substitutions must be given as a dictionary.

maxn : int, optional Allow a maximum temporary working precision of maxn digits.

chop : bool or number, optional Specifies how to replace tiny real or imaginary parts in subresults by exact zeros.

When ``True`` the chop value defaults to standard precision.

Otherwise the chop value is used to determine the
magnitude of "small" for purposes of chopping.

>>> from sympy import N
>>> x = 1e-4
>>> N(x, chop=True)
0.000100000000000000
>>> N(x, chop=1e-5)
0.000100000000000000
>>> N(x, chop=1e-4)
0

strict : bool, optional Raise PrecisionExhausted if any subresult fails to evaluate to full accuracy, given the available maxprec.

quad : str, optional Choose algorithm for numerical quadrature. By default, tanh-sinh quadrature is used. For oscillatory integrals on an infinite interval, try quad='osc'.

verbose : bool, optional Print debug information.

Notes

When Floats are naively substituted into an expression, precision errors may adversely affect the result. For example, adding 1e16 (a Float) to 1 will truncate to 1e16; if 1e16 is then subtracted, the result will be 0. That is exactly what happens in the following:

from sympy.abc import x, y, z values = {x: 1e16, y: 1, z: 1e16} (x + y - z).subs(values) 0

Using the subs argument for evalf is the accurate way to evaluate such an expression:

(x + y - z).evalf(subs=values) 1.00000000000000

normal

def normal(
    self
)

Return the expression as a fraction.

expression -> a/b

See Also

as_numer_denom: return (a, b) instead of a/b

nseries

def nseries(
    self,
    x=None,
    x0=0,
    n=6,
    dir='+',
    logx=None,
    cdir=0
)

Wrapper to _eval_nseries if assumptions allow, else to series.

If x is given, x0 is 0, dir='+', and self has x, then _eval_nseries is called. This calculates "n" terms in the innermost expressions and then builds up the final series just by "cross-multiplying" everything out.

The optional logx parameter can be used to replace any log(x) in the returned series with a symbolic value to avoid evaluating log(x) at 0. A symbol to use in place of log(x) should be provided.

Advantage -- it's fast, because we do not have to determine how many terms we need to calculate in advance.

Disadvantage -- you may end up with less terms than you may have expected, but the O(x**n) term appended will always be correct and so the result, though perhaps shorter, will also be correct.

If any of those assumptions is not met, this is treated like a wrapper to series which will try harder to return the correct number of terms.

See also lseries().

Examples

from sympy import sin, log, Symbol from sympy.abc import x, y sin(x).nseries(x, 0, 6) x - x3/6 + x5/120 + O(x6) log(x+1).nseries(x, 0, 5) x - x2/2 + x3/3 - x4/4 + O(x**5)

Handling of the logx parameter --- in the following example the expansion fails since sin does not have an asymptotic expansion at -oo (the limit of log(x) as x approaches 0):

e = sin(log(x)) e.nseries(x, 0, 6) Traceback (most recent call last): ... PoleError: ... ... logx = Symbol('logx') e.nseries(x, 0, 6, logx=logx) sin(logx)

In the following example, the expansion works but only returns self unless the logx parameter is used:

e = xy e.nseries(x, 0, 2) xy e.nseries(x, 0, 2, logx=logx) exp(logx*y)

nsimplify

def nsimplify(
    self,
    constants=(),
    tolerance=None,
    full=False
)

See the nsimplify function in sympy.simplify

powsimp

def powsimp(
    self,
    *args,
    **kwargs
)

See the powsimp function in sympy.simplify

primitive

def primitive(
    self
)

Return the positive Rational that can be extracted non-recursively

from every term of self (i.e., self is treated like an Add). This is like the as_coeff_Mul() method but primitive always extracts a positive Rational (never a negative or a Float).

Examples

from sympy.abc import x (3(x + 1)2).primitive() (3, (x + 1)2) a = (6x + 2); a.primitive() (2, 3x + 1) b = (x/2 + 3); b.primitive() (1/2, x + 6) (ab).primitive() == (1, a*b) True

radsimp

def radsimp(
    self,
    **kwargs
)

See the radsimp function in sympy.simplify

ratsimp

def ratsimp(
    self
)

See the ratsimp function in sympy.simplify

rcall

def rcall(
    self,
    *args
)

Apply on the argument recursively through the expression tree.

This method is used to simulate a common abuse of notation for operators. For instance, in SymPy the following will not work:

(x+Lambda(y, 2*y))(z) == x+2*z,

however, you can use:

from sympy import Lambda from sympy.abc import x, y, z (x + Lambda(y, 2y)).rcall(z) x + 2z

refine

def refine(
    self,
    assumption=True
)

See the refine function in sympy.assumptions

removeO

def removeO(
    self
)

Removes the additive O(..) symbol if there is one

replace

def replace(
    self,
    query,
    value,
    map=False,
    simultaneous=True,
    exact=None
)

Replace matching subexpressions of self with value.

If map = True then also return the mapping {old: new} where old was a sub-expression found with query and new is the replacement value for it. If the expression itself does not match the query, then the returned value will be self.xreplace(map) otherwise it should be self.subs(ordered(map.items())).

Traverses an expression tree and performs replacement of matching subexpressions from the bottom to the top of the tree. The default approach is to do the replacement in a simultaneous fashion so changes made are targeted only once. If this is not desired or causes problems, simultaneous can be set to False.

In addition, if an expression containing more than one Wild symbol is being used to match subexpressions and the exact flag is None it will be set to True so the match will only succeed if all non-zero values are received for each Wild that appears in the match pattern. Setting this to False accepts a match of 0; while setting it True accepts all matches that have a 0 in them. See example below for cautions.

The list of possible combinations of queries and replacement values is listed below:

Examples

Initial setup

from sympy import log, sin, cos, tan, Wild, Mul, Add from sympy.abc import x, y f = log(sin(x)) + tan(sin(x**2))

1.1. type -> type obj.replace(type, newtype)

When object of type ``type`` is found, replace it with the
result of passing its argument(s) to ``newtype``.

>>> f.replace(sin, cos)
log(cos(x)) + tan(cos(x**2))
>>> sin(x).replace(sin, cos, map=True)
(cos(x), {sin(x): cos(x)})
>>> (x*y).replace(Mul, Add)
x + y

1.2. type -> func obj.replace(type, func)

When object of type ``type`` is found, apply ``func`` to its
argument(s). ``func`` must be written to handle the number
of arguments of ``type``.

>>> f.replace(sin, lambda arg: sin(2*arg))
log(sin(2*x)) + tan(sin(2*x**2))
>>> (x*y).replace(Mul, lambda *args: sin(2*Mul(*args)))
sin(2*x*y)

2.1. pattern -> expr obj.replace(pattern(wild), expr(wild))

Replace subexpressions matching ``pattern`` with the expression
written in terms of the Wild symbols in ``pattern``.

>>> a, b = map(Wild, 'ab')
>>> f.replace(sin(a), tan(a))
log(tan(x)) + tan(tan(x**2))
>>> f.replace(sin(a), tan(a/2))
log(tan(x/2)) + tan(tan(x**2/2))
>>> f.replace(sin(a), a)
log(x) + tan(x**2)
>>> (x*y).replace(a*x, a)
y

Matching is exact by default when more than one Wild symbol
is used: matching fails unless the match gives non-zero
values for all Wild symbols:

>>> (2*x + y).replace(a*x + b, b - a)
y - 2
>>> (2*x).replace(a*x + b, b - a)
2*x

When set to False, the results may be non-intuitive:

>>> (2*x).replace(a*x + b, b - a, exact=False)
2/x

2.2. pattern -> func obj.replace(pattern(wild), lambda wild: expr(wild))

All behavior is the same as in 2.1 but now a function in terms of
pattern variables is used rather than an expression:

>>> f.replace(sin(a), lambda a: sin(2*a))
log(sin(2*x)) + tan(sin(2*x**2))

3.1. func -> func obj.replace(filter, func)

Replace subexpression ``e`` with ``func(e)`` if ``filter(e)``
is True.

>>> g = 2*sin(x**3)
>>> g.replace(lambda expr: expr.is_Number, lambda expr: expr**2)
4*sin(x**9)

The expression itself is also targeted by the query but is done in such a fashion that changes are not made twice.

>>> e = x*(x*y + 1)
>>> e.replace(lambda x: x.is_Mul, lambda x: 2*x)
2*x*(2*x*y + 1)

When matching a single symbol, exact will default to True, but this may or may not be the behavior that is desired:

Here, we want exact=False:

from sympy import Function f = Function('f') e = f(1) + f(0) q = f(a), lambda a: f(a + 1) e.replace(q, exact=False) f(1) + f(2) e.replace(q, exact=True) f(0) + f(2)

But here, the nature of matching makes selecting the right setting tricky:

e = x(1 + y) (x(1 + y)).replace(x(1 + a), lambda a: x-a, exact=False) x (x(1 + y)).replace(x(1 + a), lambda a: x-a, exact=True) x(-x - y + 1) (xy).replace(x(1 + a), lambda a: x-a, exact=False) x (xy).replace(x(1 + a), lambda a: x-a, exact=True) x**(1 - y)

It is probably better to use a different form of the query that describes the target expression more precisely:

(1 + x(1 + y)).replace( ... lambda x: x.is_Pow and x.exp.is_Add and x.exp.args[0] == 1, ... lambda x: x.base(1 - (x.exp - 1))) ... x**(1 - y) + 1

See Also

subs: substitution of subexpressions as defined by the objects themselves. xreplace: exact node replacement in expr tree; also capable of using matching rules

rewrite

def rewrite(
    self,
    *args,
    deep=True,
    **hints
)

Rewrite self using a defined rule.

Rewriting transforms an expression to another, which is mathematically equivalent but structurally different. For example you can rewrite trigonometric functions as complex exponentials or combinatorial functions as gamma function.

This method takes a pattern and a rule as positional arguments. pattern is optional parameter which defines the types of expressions that will be transformed. If it is not passed, all possible expressions will be rewritten. rule defines how the expression will be rewritten.

Parameters

args : Expr A rule, or pattern and rule. - pattern is a type or an iterable of types. - rule can be any object.

deep : bool, optional If True, subexpressions are recursively transformed. Default is True.

Examples

If pattern is unspecified, all possible expressions are transformed.

from sympy import cos, sin, exp, I from sympy.abc import x expr = cos(x) + Isin(x) expr.rewrite(exp) exp(Ix)

Pattern can be a type or an iterable of types.

expr.rewrite(sin, exp) exp(Ix)/2 + cos(x) - exp(-Ix)/2 expr.rewrite([cos,], exp) exp(Ix)/2 + Isin(x) + exp(-Ix)/2 expr.rewrite([cos, sin], exp) exp(Ix)

Rewriting behavior can be implemented by defining _eval_rewrite() method.

from sympy import Expr, sqrt, pi class MySin(Expr): ... def _eval_rewrite(self, rule, args, hints): ... x, = args ... if rule == cos: ... return cos(pi/2 - x, evaluate=False) ... if rule == sqrt: ... return sqrt(1 - cos(x)2) MySin(MySin(x)).rewrite(cos) cos(-cos(-x + pi/2) + pi/2) MySin(x).rewrite(sqrt) sqrt(1 - cos(x)**2)

Defining _eval_rewrite_as_[...]() method is supported for backwards compatibility reason. This may be removed in the future and using it is discouraged.

class MySin(Expr): ... def _eval_rewrite_as_cos(self, args, *hints): ... x, = args ... return cos(pi/2 - x, evaluate=False) MySin(x).rewrite(cos) cos(-x + pi/2)

round

def round(
    self,
    n=None
)

Return x rounded to the given decimal place.

If a complex number would results, apply round to the real and imaginary components of the number.

Examples

from sympy import pi, E, I, S, Number pi.round() 3 pi.round(2) 3.14 (2pi + EI).round() 6 + 3*I

The round method has a chopping effect:

(2pi + I/10).round() 6 (pi/10 + 2I).round() 2I (pi/10 + EI).round(2) 0.31 + 2.72*I

Notes

The Python round function uses the SymPy round method so it will always return a SymPy number (not a Python float or int):

isinstance(round(S(123), -2), Number) True

separate

def separate(
    self,
    deep=False,
    force=False
)

See the separate function in sympy.simplify

series

def series(
    self,
    x=None,
    x0=0,
    n=6,
    dir='+',
    logx=None,
    cdir=0
)

Series expansion of "self" around x = x0 yielding either terms of

the series one by one (the lazy series given when n=None), else all the terms at once when n != None.

Returns the series expansion of "self" around the point x = x0 with respect to x up to O((x - x0)**n, x, x0) (default n is 6).

If x=None and self is univariate, the univariate symbol will be supplied, otherwise an error will be raised.

Parameters

expr : Expression The expression whose series is to be expanded.

x : Symbol It is the variable of the expression to be calculated.

x0 : Value The value around which x is calculated. Can be any value from -oo to oo.

n : Value The value used to represent the order in terms of x**n, up to which the series is to be expanded.

dir : String, optional The series-expansion can be bi-directional. If dir="+", then (x->x0+). If dir="-", then (x->x0-). For infinitex0(ooor-oo), thedirargument is determined from the direction of the infinity (i.e.,dir="-"foroo``).

logx : optional It is used to replace any log(x) in the returned series with a symbolic value rather than evaluating the actual value.

cdir : optional It stands for complex direction, and indicates the direction from which the expansion needs to be evaluated.

Examples

from sympy import cos, exp, tan from sympy.abc import x, y cos(x).series() 1 - x2/2 + x4/24 + O(x6) cos(x).series(n=4) 1 - x2/2 + O(x4) cos(x).series(x, x0=1, n=2) cos(1) - (x - 1)*sin(1) + O((x - 1)2, (x, 1)) e = cos(x + exp(y)) e.series(y, n=2) cos(x + 1) - ysin(x + 1) + O(y2) e.series(x, n=2) cos(exp(y)) - xsin(exp(y)) + O(x**2)

If n=None then a generator of the series terms will be returned.

term=cos(x).series(n=None) [next(term) for i in range(2)] [1, -x**2/2]

For dir=+ (default) the series is calculated from the right and for dir=- the series from the left. For smooth functions this flag will not alter the results.

abs(x).series(dir="+") x abs(x).series(dir="-") -x f = tan(x) f.series(x, 2, 6, "+") tan(2) + (1 + tan(2)2)*(x - 2) + (x - 2)2(tan(2)3 + tan(2)) + (x - 2)3(1/3 + 4tan(2)2/3 + tan(2)4) + (x - 2)4(tan(2)5 + 5*tan(2)3/3 + 2tan(2)/3) + (x - 2)5(2/15 + 17tan(2)2/15 + 2tan(2)4 + tan(2)6) + O((x - 2)**6, (x, 2))

f.series(x, 2, 3, "-") tan(2) + (2 - x)(-tan(2)2 - 1) + (2 - x)2(tan(2)3 + tan(2)) + O((x - 2)3, (x, 2))

For rational expressions this method may return original expression without the Order term.

(1/x).series(x, n=8) 1/x

Returns

Expr : Expression Series expansion of the expression about x0

Raises

TypeError If "n" and "x0" are infinity objects

PoleError If "x0" is an infinity object

simplify

def simplify(
    self,
    **kwargs
)

See the simplify function in sympy.simplify

sort_key

def sort_key(
    self,
    order=None
)

Return a sort key.

Examples

from sympy import S, I

sorted([S(1)/2, I, -I], key=lambda x: x.sort_key()) [1/2, -I, I]

S("[x, 1/x, 1/x2, x2, x(1/2), x(1/4), x(3/2)]") [x, 1/x, x(-2), x2, sqrt(x), x(1/4), x(3/2)] sorted(_, key=lambda x: x.sort_key()) [x(-2), 1/x, x(1/4), sqrt(x), x, x(3/2), x**2]

subs

def subs(
    self,
    *args,
    **kwargs
)

Substitutes old for new in an expression after sympifying args.

args is either: - two arguments, e.g. foo.subs(old, new) - one iterable argument, e.g. foo.subs(iterable). The iterable may be o an iterable container with (old, new) pairs. In this case the replacements are processed in the order given with successive patterns possibly affecting replacements already made. o a dict or set whose key/value items correspond to old/new pairs. In this case the old/new pairs will be sorted by op count and in case of a tie, by number of args and the default_sort_key. The resulting sorted list is then processed as an iterable container (see previous).

If the keyword simultaneous is True, the subexpressions will not be evaluated until all the substitutions have been made.

Examples

from sympy import pi, exp, limit, oo from sympy.abc import x, y (1 + xy).subs(x, pi) piy + 1 (1 + xy).subs({x:pi, y:2}) 1 + 2pi (1 + xy).subs([(x, pi), (y, 2)]) 1 + 2pi reps = [(y, x2), (x, 2)] (x + y).subs(reps) 6 (x + y).subs(reversed(reps)) x2 + 2

(x2 + x4).subs(x2, y) y2 + y

To replace only the x2 but not the x4, use xreplace:

(x2 + x4).xreplace({x2: y}) x4 + y

To delay evaluation until all substitutions have been made, set the keyword simultaneous to True:

(x/y).subs([(x, 0), (y, 0)]) 0 (x/y).subs([(x, 0), (y, 0)], simultaneous=True) nan

This has the added feature of not allowing subsequent substitutions to affect those already made:

((x + y)/y).subs({x + y: y, y: x + y}) 1 ((x + y)/y).subs({x + y: y, y: x + y}, simultaneous=True) y/(x + y)

In order to obtain a canonical result, unordered iterables are sorted by count_op length, number of arguments and by the default_sort_key to break any ties. All other iterables are left unsorted.

from sympy import sqrt, sin, cos from sympy.abc import a, b, c, d, e

A = (sqrt(sin(2x)), a) B = (sin(2x), b) C = (cos(2*x), c) D = (x, d) E = (exp(x), e)

expr = sqrt(sin(2x))sin(exp(x)x)cos(2x) + sin(2x)

expr.subs(dict([A, B, C, D, E])) acsin(d*e) + b

The resulting expression represents a literal replacement of the old arguments with the new arguments. This may not reflect the limiting behavior of the expression:

(x*3 - 3x).subs({x: oo}) nan

limit(x*3 - 3x, x, oo) oo

If the substitution will be followed by numerical evaluation, it is better to pass the substitution to evalf as

(1/x).evalf(subs={x: 3.0}, n=21) 0.333333333333333333333

rather than

(1/x).subs({x: 3.0}).evalf(21) 0.333333333333333314830

as the former will ensure that the desired level of precision is obtained.

See Also

replace: replacement capable of doing wildcard-like matching, parsing of match, and conditional replacements xreplace: exact node replacement in expr tree; also capable of using matching rules sympy.core.evalf.EvalfMixin.evalf: calculates the given formula to a desired level of precision

taylor_term

def taylor_term(
    self,
    n,
    x,
    *previous_terms
)

General method for the taylor term.

This method is slow, because it differentiates n-times. Subclasses can redefine it to make it faster by using the "previous_terms".

to_nnf

def to_nnf(
    self,
    simplify=True
)

together

def together(
    self,
    *args,
    **kwargs
)

See the together function in sympy.polys

transpose

def transpose(
    self
)

trigsimp

def trigsimp(
    self,
    **args
)

See the trigsimp function in sympy.simplify

xreplace

def xreplace(
    self,
    rule,
    hack2=False
)

Replace occurrences of objects within the expression.

Parameters

rule : dict-like Expresses a replacement rule

Returns

xreplace : the result of the replacement

Examples

from sympy import symbols, pi, exp x, y, z = symbols('x y z') (1 + xy).xreplace({x: pi}) piy + 1 (1 + xy).xreplace({x: pi, y: 2}) 1 + 2pi

Replacements occur only if an entire node in the expression tree is matched:

(xy + z).xreplace({xy: pi}) z + pi (xyz).xreplace({xy: pi}) xyz (2x).xreplace({2x: y, x: z}) y (22x).xreplace({2x: y, x: z}) 4*z (x + y + 2).xreplace({x + y: 2}) x + y + 2 (x + 2 + exp(x + 2)).xreplace({x + 2: y}) x + exp(y) + 2

xreplace does not differentiate between free and bound symbols. In the following, subs(x, y) would not change x since it is a bound symbol, but xreplace does:

from sympy import Integral Integral(x, (x, 1, 2x)).xreplace({x: y}) Integral(y, (y, 1, 2y))

Trying to replace x with an expression raises an error:

Integral(x, (x, 1, 2x)).xreplace({x: 2y}) # doctest: +SKIP ValueError: Invalid limits given: ((2y, 1, 4y),)

See Also

replace: replacement capable of doing wildcard-like matching, parsing of match, and conditional replacements subs: substitution of subexpressions as defined by the objects themselves.

ParameterReference

class ParameterReference(
    workflow: 'Workflow',
    parameter: 'Parameter[RawType]'
)

Reference to an individual Parameter.

Allows us to refer to the outputs of a Parameter in subsequent Parameter arguments.

Attributes

Name Type Description Default
parameter None Parameter referred to. None

Ancestors (in MRO)

  • dewret.workflow.Reference

Instance variables

name

Reference based on the named step.

May be remapped by the workflow to something nicer than the ID.

Raw

class Raw(
    value: 'RawType'
)

Value object for any raw types.

This is able to hash raw types consistently and provides a single type for validating type-consistency.

Attributes

Name Type Description Default
value None the real value, e.g. a str, int, ... None

Instance variables

value

Reference

class Reference(
    /,
    *args,
    **kwargs
)

Superclass for all symbolic references to values.

Descendants

  • dewret.workflow.ParameterReference
  • dewret.workflow.StepReference

Instance variables

name

Referral name for this reference.

Step

class Step(
    workflow: 'Workflow',
    task: 'Task',
    arguments: 'Mapping[str, Reference | Raw]'
)

Lazy-evaluated function call.

Individual function call to a lazy-evaluatable function, tracked for building up the Workflow.

Attributes

Name Type Description Default
task None the Task being called in this step. None
arguments None key-value pairs of arguments to this step. None

Ancestors (in MRO)

  • dewret.workflow.WorkflowComponent

Instance variables

id

Consistent ID based on the value.

name

Name for this step.

May be remapped by the workflow to something nicer than the ID.

return_type

Take the type of the wrapped function from the target.

Unwraps and inspects the signature, meaning that the original wrapped function must have a typehint for the return value.

Methods

set_workflow

def set_workflow(
    self,
    workflow: 'Workflow'
) -> 'None'

Move the step reference to another workflow.

Primarily intended to be called by its step, as a cascade. It will attempt to update its arguments, similarly.

Parameters:

Name Type Description Default
workflow None the new target workflow. None

StepReference

class StepReference(
    workflow: 'Workflow',
    step: 'Step',
    typ: 'type[U]',
    field: 'str | None' = None
)

Reference to an individual Step.

Allows us to refer to the outputs of a Step in subsequent Step arguments.

Attributes

Name Type Description Default
step None Step referred to. None

Ancestors (in MRO)

  • typing.Generic
  • dewret.workflow.Reference

Instance variables

field

Field within the result.

Explicitly set field (within an attrs-class) or out.

name

Reference based on the named step.

May be remapped by the workflow to something nicer than the ID.

return_type

Type that this step reference will resolve to.

Task

class Task(
    name: 'str',
    target: 'Lazy'
)

Named wrapper of a lazy-evaluatable function.

Wraps a lazy-evaluatable function (dewret.workflow.Lazy) with any metadata needed to render it later. At present, this is the name.

Attributes

Name Type Description Default
name None Name of the lazy function as it will appear in the output workflow text. None
target None Callable that is wrapped. None

Workflow

class Workflow(
    
)

Overarching workflow concept.

Represents a whole workflow, as a singleton maintaining all state information needed ahead of rendering. It is built up as the lazy-evaluations are finally evaluated.

Attributes

Name Type Description Default
steps None the sequence of calls to lazy-evaluable functions,
built as they are evaluated.
None
tasks None the mapping of names used in the steps to the actual
Task wrappers they represent.
None
result None target reference to evaluate, if yet present. None

Static methods

assimilate

def assimilate(
    left: 'Workflow',
    right: 'Workflow'
) -> "'Workflow'"

Combine two Workflows into one Workflow.

Takes two workflows and unifies them by combining steps and tasks. If it sees mismatched identifiers for the same component, it will error. This could happen if the hashing function is flawed or some Python magic to do with Targets being passed.

Argument: left: workflow to use as base right: workflow to combine on top

from_result

def from_result(
    result: 'StepReference[Any]',
    simplify_ids: 'bool' = False
) -> 'Workflow'

Create from a desired result.

Starts from a result, and builds a workflow to output it.

Methods

add_step

def add_step(
    self,
    fn: 'Lazy',
    kwargs: 'dict[str, Raw | Reference]'
) -> 'StepReference[Any]'

Append a step.

Adds a step, for running a target with key-value arguments, to the workflow.

Parameters:

Name Type Description Default
fn None the target function to turn into a step. None
kwargs None any key-value arguments to pass in the call. None

find_parameters

def find_parameters(
    self
) -> 'set[ParameterReference]'

Crawl steps for parameter references.

As the workflow does not hold its own list of parameters, this dynamically finds them.

Returns:

Type Description
None Set of all references to parameters across the steps.

register_task

def register_task(
    self,
    fn: 'Lazy'
) -> 'Task'

Note the existence of a lazy-evaluatable function, and wrap it as a Task.

Parameters:

Name Type Description Default
fn None the wrapped function. None

Returns:

Type Description
None A new Task that wraps the function, and is retained in the Workflow.tasks
dict.

remap

def remap(
    self,
    step_id: 'str'
) -> 'str'

Apply name simplification if requested.

Parameters:

Name Type Description Default
step_id None step to check. None

Returns:

Type Description
None Same ID or a remapped name.

set_result

def set_result(
    self,
    result: 'StepReference[Any]'
) -> 'None'

Choose the result step.

Sets a step as being the result for the entire workflow. When we evaluate a dynamic workflow, the engine (e.g. dask) creates a graph to realize the result of a single collection. Similarly, in the static case, we need to have a result that drives the calculation.

Parameters:

Name Type Description Default
result None reference to the chosen step. None

simplify_ids

def simplify_ids(
    self
) -> 'None'

Work out mapping to simple ints from hashes.

Goes through and numbers each step by the order of use of its task.

WorkflowComponent

class WorkflowComponent(
    workflow: 'Workflow'
)

Base class for anything directly tied to an individual Workflow.

Attributes

Name Type Description Default
workflow None the Workflow that this is tied to. None

Descendants

  • dewret.workflow.Step

WorkflowLinkedComponent

class WorkflowLinkedComponent(
    *args,
    **kwargs
)

Protocol for objects dynamically tied to a Workflow.

Ancestors (in MRO)

  • typing.Protocol
  • typing.Generic