By default a coefficient of a term in Symbolica is a rational number. For example in the expression

\[ 3 x \epsilon + \frac{1}{2}x \]

the coefficients are \(3\) and \(\frac{1}{2}\).

For many applications it is favourable to extend the coefficient ring to include variables. If we consider \(\epsilon\) to be part of the coefficient, we get:

\[ \frac{1 + 6 \epsilon}{2} x \]

For example, when coding the following iterative replacement rule:

\[ I(n) = I(n-1) \frac{2 + (4-2 \epsilon) - 2 n}{2(n - 1) m^2}\,; n \geq 1 \]

a possible Symbolica code is:

from symbolica import *
ep, m, n_ = Expression.symbols('ep', 'm', 'n_')
topo = Expression.symbol('topo')
T = Transformer()

e = topo(10).transform().repeat(
                        topo(n_ - 1) * (2 + (4-2*ep) - 2 * n_) /
                        (2*(n_ - 1)) / m**2,

which yields


At each stage, the pattern matcher will match and replace a topo(n) in every term, and will create new terms for every power of ep. This overhead can be avoided by considering ep to be a part of the coefficient. Then we have topo(2)*ep+topo(2) = topo(2)*(ep+1).

We use Expression.COEFF (State::COEFF in Rust) that converts its rational polynomial argument to a coefficient:

e = topo(10).transform().repeat(
                          topo(n_ - 1)
                          *Expression.COEFF((2 + (4-2*ep) -
                                         2 * n_)/(2*(n_ - 1))) / m**2,

This code is much faster and the expression looks like:


where [...] indicates that the contained rational polynomial is a coefficient.

Since it is a coefficient, we cannot pattern match on the internal structure. To do these operations, we can convert back from a number to an atom using from_coeff:

e = e.replace_all(n_, n_.transform().from_coeff(), n_.req_type(AtomType.Num))

Now we get:


Coefficient rings

The coefficient ring can also be changed using the set_coefficient_ring function which takes the variables that should be considered part of the coefficient as an argument. It will then rewrite the expression.

from symbolica import Expression
x, y, z = Expression.symbols('x', 'y', 'z')
e = x*z+x*(y+2)**-1*(y+z+1)
print(e.set_coefficient_ring([y, z]))
use std::sync::Arc;
use symbolica::atom::Atom;

fn main() {
    let expr = Atom::parse("x*z+x*(y+2)^-1*(y+z+1)").unwrap();
    println!("> In: {}", expr);

    let expr_yz = expr.set_coefficient_ring(
    println!("> Coefficient ring y,z: {}", expr_yz);

which yields