Transformer

Transformer

Transformer()

Operations that transform an expression.

Methods

Name Description
__call__ Execute an unbound transformer on the given expression
__eq__ Compare two transformers.
__ge__ Compare two transformers
__gt__ Compare two transformers
__le__ Compare two transformers
__lt__ Compare two transformers
__neq__ Compare two transformers.
__new__ Create a new transformer for a term provided by Expression.map.
apart Create a transformer that computes the partial fraction decomposition in x.
break_chain Break the current chain and all higher-level chains containing if transformers.
cancel Create a transformer that cancels common factors between numerators and denominators
chain Chain several transformers
check_interrupt Create a transformer that checks for a Python interrupt, such as ctrl-c and aborts the current transformer.
coefficient Create a transformer that collects terms involving the literal occurrence of x.
collect Create a transformer that collects terms involving the same power of the indeterminate(s) x
collect_factors Create a transformer that collects common factors from (nested) sums.
collect_horner Create a transformer that iteratively extracts the minimal common powers of an indeterminate v for every term that contains v and continues to the next indeterminate in variables
collect_num Create a transformer that collects numerical factors by removing the content from additions
collect_symbol Create a transformer that collects terms involving the same power of variables or functions with the name x
conjugate Complex conjugate the expression.
contains Create a transformer that checks if the expression contains the given element.
cycle_symmetrize Create a transformer that cycle-symmetrizes a function.
deduplicate Create a transformer that removes elements from a list if they occur earlier in the list as well.
derivative Create a transformer that derives self w.r.t the variable x.
expand Create a transformer that expands products and powers
expand_num Create a transformer that distributes numbers in the expression, for example: 2*(x+y) -> 2*x+2*y.
factor Create a transformer that factors the expression over the rationals.
for_each Create a transformer that applies a transformer chain to every argument of the arg() function
from_coeff Create a transformer that extracts a rational polynomial from a coefficient.
if_changed Execute the condition transformer
if_then Evaluate the condition and apply the if_block if the condition is true, otherwise apply the else_block
is_type Test if the transformed expression is of a certain type.
linearize Create a transformer that linearizes a function, optionally extracting symbols as well.
map Create a transformer that applies a Python function.
map_terms Map a chain of transformer over the terms of the expression, optionally using multiple cores.
matches Create a transformer that tests whether the pattern is found in the expression
nargs Create a transformer that returns the number of arguments
partitions Create a transformer that partitions a list of arguments into named bins of a given length, returning all partitions and their multiplicity
permutations Create a transformer that generates all permutations of a list of arguments.
print Create a transformer that prints the expression.
prod Create a transformer that computes the product of a list of arguments.
repeat Create a transformer that repeatedly executes the arguments in order until there are no more changes
replace Create a transformer that replaces all subexpressions matching the pattern pat by the right-hand side rhs.
replace_multiple Create a transformer that replaces all atoms matching the patterns
series Create a transformer that series expands in x around expansion_point to depth depth.
set_coefficient_ring Create a transformer that sets the coefficient ring to contain the variables in the vars list
sort Create a transformer that sorts a list of arguments.
split Create a transformer that split a sum or product into a list of arguments.
stats Print statistics of a transformer, tagging it with tag.
sum Create a transformer that computes the sum of a list of arguments.
together Create a transformer that writes the expression over a common denominator.

__call__

Transformer.__call__(
    expr: Expression | int | float | complex | Decimal,
    stats_to_file: Optional[str] = None,
) -> Expression

Execute an unbound transformer on the given expression. If the transformer is bound, use execute() instead.

Examples

x = S('x')
e = T().expand()((1+x)**2)

Parameters

  • expr (Expression) The expression to transform.
  • stats_to_file (str, optional) If set, the output of the stats transformer will be written to a file in JSON format.

__eq__

Transformer.__eq__(other: Transformer | Expression | int | float | Decimal) -> Condition

Compare two transformers.

__ge__

Transformer.__ge__(other: Transformer | Expression | int | float | Decimal) -> Condition

Compare two transformers. If any of the two expressions is not a rational number, an interal ordering is used.

__gt__

Transformer.__gt__(other: Transformer | Expression | int | float | Decimal) -> Condition

Compare two transformers. If any of the two expressions is not a rational number, an interal ordering is used.

__le__

Transformer.__le__(other: Transformer | Expression | int | float | Decimal) -> Condition

Compare two transformers. If any of the two expressions is not a rational number, an interal ordering is used.

__lt__

Transformer.__lt__(other: Transformer | Expression | int | float | Decimal) -> Condition

Compare two transformers. If any of the two expressions is not a rational number, an interal ordering is used.

__neq__

Transformer.__neq__(other: Transformer | Expression | int | float | Decimal) -> Condition

Compare two transformers.

__new__

Transformer.__new__() -> Transformer

Create a new transformer for a term provided by Expression.map.

apart

Transformer.apart(x: Expression) -> Transformer

Create a transformer that computes the partial fraction decomposition in x.

break_chain

Transformer.break_chain() -> Transformer

Break the current chain and all higher-level chains containing if transformers.

Examples

from symbolica import *
t = T().map_terms(T().repeat(
    T().replace(y, 4),
    T().if_changed(T().replace(x, y),
                T().break_chain()),
    T().print()  # print of y is never reached
))
print(t(x))

cancel

Transformer.cancel() -> Transformer

Create a transformer that cancels common factors between numerators and denominators. Any non-canceling parts of the expression will not be rewritten.

chain

Transformer.chain(*transformers: Transformer) -> Transformer

Chain several transformers. chain(A,B,C) is the same as A.B.C, where A, B, C are transformers.

Examples

from symbolica import *
x_ = S('x_')
f = S('f')
e = E("f(5)")
t = T().chain(
    T().expand(),
    T().replace(f(x_), f(5))
)
e = t(f(5))

check_interrupt

Transformer.check_interrupt() -> Transformer

Create a transformer that checks for a Python interrupt, such as ctrl-c and aborts the current transformer.

Examples

from symbolica import *
x_ = S('x_')
f = S('f')
t = T().replace(f(x_), f(x_ + 1)).check_interrupt()
t(f(10))

coefficient

Transformer.coefficient(x: Expression) -> Transformer

Create a transformer that collects terms involving the literal occurrence of x.

collect

Transformer.collect(
    *x: Expression,
    key_map: Optional[Transformer] = None,
    coeff_map: Optional[Transformer] = None,
) -> Transformer

Create a transformer that collects terms involving the same power of the indeterminate(s) x. Return the list of key-coefficient pairs and the remainder that matched no key.

Both the key (the quantity collected in) and its coefficient can be mapped using key_map and coeff_map transformers respectively.

Examples

from symbolica import *
x, y = S('x', 'y')
e = 5*x + x * y + x**2 + 5

print(e.hold(T().collect(x).execute()))

yields x^2+x*(y+5)+5.

from symbolica import *
x, y, x_, var, coeff = S('x', 'y', 'x_', 'var', 'coeff')
e = 5*x + x * y + x**2 + 5
print(e.collect(x, key_map=T().replace(x_, var(x_)),
        coeff_map=T().replace(x_, coeff(x_))))

yields var(1)*coeff(5)+var(x)*coeff(y+5)+var(x^2)*coeff(1).

Parameters

  • *x (Expression) The variable(s) or function(s) to collect terms in
  • key_map (Transformer) A transformer to be applied to the quantity collected in
  • coeff_map (Transformer) A transformer to be applied to the coefficient

collect_factors

Transformer.collect_factors() -> Transformer

Create a transformer that collects common factors from (nested) sums.

Examples

from symbolica import *
t = T().collect_factors()
t(E('x*(x+y*x+x^2+y*(x+x^2))'))

yields

v1^2*(1+v1+v2+v2*(1+v1))

collect_horner

Transformer.collect_horner(vars: Sequence[Expression] | None = None) -> Transformer

Create a transformer that iteratively extracts the minimal common powers of an indeterminate v for every term that contains v and continues to the next indeterminate in variables. This is a generalization of Horner’s method for polynomials.

If no variables are provided, a heuristically determined variable ordering is used that minimizes the number of operations.

Examples

from symbolica import *
expr = E('v1 + v1*v2 + 2 v1*v2*v3 + v1^2 + v1^3*y + v1^4*z')
collected = expr.hold(T().collect_horner([S('v1'), S('v2')]))()

yields v1*(1+v1*(1+v1*(v1*z+y))+v2*(1+2*v3)).

collect_num

Transformer.collect_num() -> Transformer

Create a transformer that collects numerical factors by removing the content from additions. For example, -2*x + 4*x^2 + 6*x^3 will be transformed into -2*(x - 2*x^2 - 3*x^3).

The first argument of the addition is normalized to a positive quantity.

Examples

from symbolica import *
x, y = S('x', 'y')
e = (-3*x+6*y)*(2*x+2*y)
print(T().collect_num()(e))

yields

-6*(x+y)*(x-2*y)

collect_symbol

Transformer.collect_symbol(
    x: Expression,
    key_map: Optional[Callable[[Expression], Expression]] = None,
    coeff_map: Optional[Callable[[Expression], Expression]] = None,
) -> Transformer

Create a transformer that collects terms involving the same power of variables or functions with the name x.

Both the key (the quantity collected in) and its coefficient can be mapped using key_map and coeff_map respectively.

Examples

from symbolica import *
x, f = S('x', 'f')
e = f(1,2) + x*f(1,2)

print(T().collect_symbol(x)(e))

yields (1+x)*f(1,2).

Parameters

  • x (Expression) The symbol to collect in
  • key_map (Transformer) A transformer to be applied to the quantity collected in
  • coeff_map (Transformer) A transformer to be applied to the coefficient

conjugate

Transformer.conjugate() -> Transformer

Complex conjugate the expression.

contains

Transformer.contains(element: Transformer | HeldExpression | Expression | int | float | Decimal) -> Condition

Create a transformer that checks if the expression contains the given element.

cycle_symmetrize

Transformer.cycle_symmetrize() -> Transformer

Create a transformer that cycle-symmetrizes a function.

Examples

from symbolica import *
x_ = S('x__')
f = S('f')
e = f(1,2,4,1,2,3).replace(f(x__), x_.hold(T().cycle_symmetrize()))
print(e)

Yields f(1,2,3,1,2,4).

deduplicate

Transformer.deduplicate() -> Transformer

Create a transformer that removes elements from a list if they occur earlier in the list as well.

Examples

from symbolica import *
x__ = S('x__')
f = S('f')
e = f(1,2,1,2).replace(f(x__), x__.hold(T().deduplicate()))
print(e)

Yields f(1,2).

derivative

Transformer.derivative(x: HeldExpression | Expression) -> Transformer

Create a transformer that derives self w.r.t the variable x.

expand

Transformer.expand(var: Optional[Expression] = None, via_poly: Optional[bool] = None) -> Transformer

Create a transformer that expands products and powers. Optionally, expand in var only.

Using via_poly=True may give a significant speedup for large expressions.

Examples

from symbolica import *
x, x_ = S('x', 'x_')
f = S('f')
e = f((x+1)**2).replace(f(x_), x_.hold(T().expand()))
print(e)

expand_num

Transformer.expand_num() -> Expression

Create a transformer that distributes numbers in the expression, for example: 2*(x+y) -> 2*x+2*y.

Examples

from symbolica import *
x, y = S('x', 'y')
e = 3*(x+y)*(4*x+5*y)
print(T().expand_num()(e))

yields

(3*x+3*y)*(4*x+5*y)

factor

Transformer.factor() -> Transformer

Create a transformer that factors the expression over the rationals.

for_each

Transformer.for_each(*transformers: Transformer) -> Transformer

Create a transformer that applies a transformer chain to every argument of the arg() function. If the input is not arg(), the transformer is applied to the input.

Examples

from symbolica import *
x = S('x')
f = S('f')
t = T().split().for_each(T().map(f))
e = t(1+x)

from_coeff

Transformer.from_coeff() -> Transformer

Create a transformer that extracts a rational polynomial from a coefficient.

Examples

from symbolica import *, Function
e = Function.COEFF((x^2+1)/y^2).hold(T().from_coeff())
print(e)

if_changed

Transformer.if_changed(
    condition: Transformer,
    if_block: Transformer,
    else_block: Optional[Transformer] = None,
) -> Transformer

Execute the condition transformer. If the result of the condition transformer is different from the input expression, apply the if_block, otherwise apply the else_block. The input expression of the if_block is the output of the condition transformer.

Examples

t = T().map_terms(T().if_changed(T().replace(x, y), T().print()))
print(t(x + y + 4))

prints

y 2*y+4

if_then

Transformer.if_then(
    condition: Condition,
    if_block: Transformer,
    else_block: Optional[Transformer] = None,
) -> Transformer

Evaluate the condition and apply the if_block if the condition is true, otherwise apply the else_block. The expression that is the input of the transformer is the input for the condition, the if_block and the else_block.

Examples

t = T().map_terms(T().if_then(T().contains(x), T().print()))
t(x + y + 4)

prints x.

is_type

Transformer.is_type(atom_type: AtomType) -> Condition

Test if the transformed expression is of a certain type.

linearize

Transformer.linearize(symbols: Optional[Sequence[Expression]]) -> Transformer

Create a transformer that linearizes a function, optionally extracting symbols as well.

Examples

from symbolica import *
x, y, z, w, f, x__ = S('x', 'y', 'z', 'w', 'f', 'x__')
e = f(x+y, 4*z*w+3).replace(f(x__), f(x__).hold(T().linearize([z])))
print(e)

yields f(x,3)+f(y,3)+4*z*f(x,w)+4*z*f(y,w).

map

Transformer.map(f: Callable[[Expression], Expression | int | float | complex | Decimal]) -> Transformer

Create a transformer that applies a Python function.

Examples

from symbolica import *
x_ = S('x_')
f = S('f')
e = f(2).replace(f(x_), x_.hold(T().map(lambda r: r**2)))
print(e)

map_terms

Transformer.map_terms(*transformers: Transformer, n_cores: int = 1) -> Transformer

Map a chain of transformer over the terms of the expression, optionally using multiple cores.

Examples

from symbolica import *
x, y = S('x', 'y')
t = T().map_terms(T().print(), n_cores=2)
e = t(x + y)

matches

Transformer.matches(
    lhs: HeldExpression | Expression | int | float | Decimal,
    cond: Optional[PatternRestriction | Condition] = None,
    min_level: int = 0,
    max_level: Optional[int] = None,
    level_range: Optional[Tuple[int, Optional[int]]] = None,
    level_is_tree_depth: bool = False,
    partial: bool = True,
    allow_new_wildcards_on_rhs: bool = False,
) -> Condition

Create a transformer that tests whether the pattern is found in the expression. Restrictions on the pattern can be supplied through cond.

nargs

Transformer.nargs(only_for_arg_fun: bool = False) -> Transformer

Create a transformer that returns the number of arguments. If the argument is not a function, return 0.

If only_for_arg_fun is True, only count the number of arguments in the arg() function and return 1 if the input is not arg. This is useful for obtaining the length of a range during pattern matching.

Examples

from symbolica import *
x__ = S('x__')
f = S('f')
e = f(2,3,4).replace(f(x__), x__.hold(T().nargs()))
print(e)

partitions

Transformer.partitions(
    bins: Sequence[Tuple[Transformer | Expression, int]],
    fill_last: bool = False,
    repeat: bool = False,
) -> Transformer

Create a transformer that partitions a list of arguments into named bins of a given length, returning all partitions and their multiplicity.

If the unordered list elements is larger than the bins, setting the flag fill_last will add all remaining elements to the last bin.

Setting the flag repeat means that the bins will be repeated to exactly fit all elements, if possible.

Note that the functions names to be provided for the bin names must be generated through Expression.var.

Examples

from symbolica import *
x_, f_id, g_id = S('x__', 'f', 'g')
f = S('f')
e = f(1,2,1,3).replace(f(x_), x_.hold(T().partitions([(f_id, 2), (g_id, 1), (f_id, 1)])))
print(e)

yields:

2*f(1)*f(1,2)*g(3)+2*f(1)*f(1,3)*g(2)+2*f(1)*f(2,3)*g(1)+f(2)*f(1,1)*g(3)+2*f(2)*f(1,3)*g(1)+f(3)*f(1,1)*g(2)+2*f(3)*f(1,2)*g(1)

permutations

Transformer.permutations(function_name: Transformer | Expression) -> Transformer

Create a transformer that generates all permutations of a list of arguments.

Examples

from symbolica import *
x_, f_id = S('x__', 'f')
f = S('f')
e = f(1,2,1,2).replace(f(x_), x_.hold(T().permutations(f_id)))
print(e)

yields:

4*f(1,1,2,2)+4*f(1,2,1,2)+4*f(1,2,2,1)+4*f(2,1,1,2)+4*f(2,1,2,1)+4*f(2,2,1,1)

print

Transformer.print(
    mode: PrintMode = PrintMode.Symbolica,
    max_line_length: int | None = 80,
    indentation: int = 4,
    fill_indented_lines: bool = True,
    terms_on_new_line: bool = False,
    color_top_level_sum: bool = True,
    color_builtin_symbols: bool = True,
    bracket_level_colors: Sequence[int] | None = [244, 25, 97, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60],
    print_ring: bool = True,
    symmetric_representation_for_finite_field: bool = False,
    explicit_rational_polynomial: bool = False,
    number_thousands_separator: Optional[str] = None,
    multiplication_operator: str = '*',
    double_star_for_exponentiation: bool = False,
    square_brackets_for_function: bool = False,
    function_brackets: tuple[str, str] = ('(', ')'),
    num_exp_as_superscript: bool = True,
    show_namespaces: bool = False,
    hide_namespace: Optional[str] = None,
    include_attributes: bool = False,
    max_terms: Optional[int] = None,
    custom_print_mode: Optional[int] = None,
) -> Transformer

Create a transformer that prints the expression.

Examples

T().print(terms_on_new_line = True)

prod

Transformer.prod() -> Transformer

Create a transformer that computes the product of a list of arguments.

Examples

from symbolica import *
x__ = S('x__')
f = S('f')
e = f(2,3).replace(f(x__), x__.hold(T().prod()))
print(e)

repeat

Transformer.repeat(*transformers: Transformer) -> Transformer

Create a transformer that repeatedly executes the arguments in order until there are no more changes. The output from one transformer is inserted into the next.

Examples

from symbolica import *
x_ = S('x_')
f = S('f')
t = T().repeat(
    T().expand(),
    T().replace(f(x_), f(x_ - 1) + f(x_ - 2), x_.req_gt(1))
)
e = t(f(5))

replace

Transformer.replace(
    pat: HeldExpression | Expression | int | float | complex | Decimal,
    rhs: HeldExpression | Expression | Callable[[dict[Expression, Expression]], Expression] | int | float | complex | Decimal,
    cond: Optional[PatternRestriction | Condition] = None,
    non_greedy_wildcards: Optional[Sequence[Expression]] = None,
    min_level: int = 0,
    max_level: Optional[int] = None,
    level_range: Optional[Tuple[int, Optional[int]]] = None,
    level_is_tree_depth: bool = False,
    partial: bool = True,
    allow_new_wildcards_on_rhs: bool = False,
    rhs_cache_size: Optional[int] = None,
    once: bool = False,
    bottom_up: bool = False,
    nested: bool = False,
) -> Transformer

Create a transformer that replaces all subexpressions matching the pattern pat by the right-hand side rhs.

Examples

x, w1_, w2_ = S('x','w1_','w2_')
f = S('f')
t = T().replace(f(w1_, w2_), f(w1_ - 1, w2_**2), w1_ >= 1)
r = t(f(3,x))
print(r)

Parameters

  • pat The pattern to match.
  • rhs The right-hand side to replace the matched subexpression with. Can be a transformer, expression or a function that maps a dictionary of wildcards to an expression.
  • cond Conditions on the pattern.
  • non_greedy_wildcards Wildcards that try to match as little as possible.
  • cond (PatternRestriction | Condition, optional) Conditions on the pattern.
  • non_greedy_wildcards (Sequence[Expression], optional) Wildcards that try to match as little as possible.
  • min_level (int, optional) The minimum level at which the pattern is allowed to match. The first level is 0 and the level is increased when going into a function or one level deeper in the expression tree, depending on level_is_tree_depth.
  • max_level (Optional[int], optional) The maximum level at which the pattern is allowed to match. None means no maximum.
  • level_range Specifies the [min,max] level at which the pattern is allowed to match. The first level is 0 and the level is increased when going into a function or one level deeper in the expression tree, depending on level_is_tree_depth. Prefer setting min_level and max_level directly over level_range, as this argument will be deprecated in the future.
  • level_is_tree_depth (bool, optional) If set to True, the level is increased when going one level deeper in the expression tree.
  • partial (bool, optional) If set to True, allow the pattern to match to a part of a term. For example, with partial=True, the pattern x+y matches to x+2+y.
  • allow_new_wildcards_on_rhs (bool, optional) If set to True, allow wildcards that do not appear in the pattern on the right-hand side.
  • rhs_cache_size (int, optional) Cache the first rhs_cache_size substituted patterns. If set to None, an internally determined cache size is used. Warning: caching should be disabled (rhs_cache_size=0) if the right-hand side contains side effects, such as updating a global variable.
  • once (bool, optional) If set to True, only the first match will be replaced, instead of all non-overlapping matches.
  • bottom_up (bool, optional) Replace deepest nested matches first instead of replacing the outermost matches first. For example, replacing f(x_) with x_^2 in f(f(x)) would yield f(x)^2 with the default settings and f(x^2) with bottom-up replacement.
  • nested (bool, optional) Replace nested matches, starting from the deepest first and acting on the result of that replacement. For example, replacing f(x_) with x_^2 in f(f(x)) would yield f(x)^2 with the default settings and f(x^2)^2 with nested replacement.

replace_multiple

Transformer.replace_multiple(
    replacements: Sequence[Replacement],
    once: bool = False,
    bottom_up: bool = False,
    nested: bool = False,
) -> Transformer

Create a transformer that replaces all atoms matching the patterns. See replace for more information.

Examples

x, y, f = S('x', 'y', 'f')
t = T().replace_multiple([Replacement(x, y), Replacement(y, x)])
r = t(f(x,y))
print(r)

series

Transformer.series(
    x: Expression,
    expansion_point: Expression | int | float | complex | Decimal,
    depth: int,
    depth_denom: int = 1,
    depth_is_absolute: bool = True,
) -> Transformer

Create a transformer that series expands in x around expansion_point to depth depth.

Examples

from symbolica import *
x, y = S('x', 'y')
f = S('f')

e = 2* x**2 * y + f(x)
e = e.series(x, 0, 2)

print(e)

yields f(0)+x*der(1,f(0))+1/2*x^2*(der(2,f(0))+4*y).

set_coefficient_ring

Transformer.set_coefficient_ring(vars: Sequence[Expression]) -> Transformer

Create a transformer that sets the coefficient ring to contain the variables in the vars list. This will move all variables into a rational polynomial function.

Parameters

  • vars (Sequence[Expression]) A list of variables

sort

Transformer.sort() -> Transformer

Create a transformer that sorts a list of arguments.

Examples

from symbolica import *
x__ = S('x__')
f = S('f')
e = f(3,2,1).replace(f(x__), x__.hold(T().sort()))
print(e)

split

Transformer.split() -> Transformer

Create a transformer that split a sum or product into a list of arguments.

Examples

from symbolica import *
x, x__ = S('x', 'x__')
f = S('f')
e = (x + 1).replace(x__, f(x_.hold(T().split())))
print(e)

stats

Transformer.stats(
    tag: str,
    transformer: Transformer,
    color_medium_change_threshold: Optional[float] = 10.0,
    color_large_change_threshold: Optional[float] = 100.0,
) -> Transformer

Print statistics of a transformer, tagging it with tag.

Examples

from symbolica import *
x_ = S('x_')
f = S('f')
t = T().stats('replace', T().replace(f(x_), 1)).execute()
t(eE('f(5)'))

yields

Stats for replace: In  │ 1 │  10.00 B │ Out │ 1 │   3.00 B │ ⧗ 40.15µs

sum

Transformer.sum() -> Transformer

Create a transformer that computes the sum of a list of arguments.

Examples

from symbolica import *
x__ = S('x__')
f = S('f')
e = f(2,3).replace(f(x__), x__.hold(T().sum()))
print(e)

together

Transformer.together() -> Transformer

Create a transformer that writes the expression over a common denominator.