Python
This page contains an overview of all classes and methods accessible through the Python API. Alternatively one can view it here.
class Expression:
A Symbolica expression.
Supports standard arithmetic operations, such as addition and multiplication.
Examples
>>> x = Expression.var('x')
>>> e = x**2 + 2 - x + 1 / x**4
>>> print(e)
def var (_cls, name: str ) -> symbolica.symbolica.Expression:
Creates a Symbolica expression that is a single variable.
Examples
>>> var_x = Expression.var('x')
>>> print(var_x)
x
def vars (_cls, *names: str ) -> Sequence[symbolica.symbolica.Expression]:
Create a Symbolica variable for every name in *names
.
def fun ( _cls, name: str, is_symmetric: bool = False ) -> symbolica.symbolica.Function:
Creates a new Symbolica function with a given name.
Examples
>>> f = Expression.fun('f')
>>> e = f(1,2)
>>> print(e)
f(1,2)
def funs (_cls, *names: str ) -> Sequence[symbolica.symbolica.Function]:
Create a Symbolica function for every name in *names
.
def parse (_cls, input: str ) -> symbolica.symbolica.Expression:
Parse a Symbolica expression from a string.
Parameters
input: str An input string. UTF-8 character are allowed.
Examples
>>> e = Expression.parse('x^2+y+y*4')
>>> print(e)
x^2+5*y
Raises
ValueError If the input is not a valid Symbolica expression.
def pretty_str ( self, terms_on_new_line: bool = False, color_top_level_sum: bool = True, color_builtin_functions: bool = True, print_finite_field: bool = True, explicit_rational_polynomial: bool = False, number_thousands_separator: Optional[str] = None, multiplication_operator: str = '*', square_brackets_for_function: bool = False, num_exp_as_superscript: bool = True, latex: bool = False) -> str:
Convert the expression into a human-readable string, with tunable settings.
Examples
>>> a = Expression.parse('128378127123 z^(2/3)*w^2/x/y + y^4 + z^34 + x^(x+2)+3/5+f(x,x^2)')
>>> print(a.pretty_str(latex=True))
def get_name (self) -> Optional[str]:
Get the name of a variable or function if the current atom is a variable or function.
def transform (self ) -> symbolica.symbolica.Transformer:
Convert the input to a transformer, on which subsequent transformations can be applied.
def req_len ( self, min_length: int, max_length: int | None ) -> symbolica.symbolica.PatternRestriction:
Create a pattern restriction based on the wildcard length before downcasting.
def req_type ( self, atom_type: symbolica.symbolica.AtomType ) -> symbolica.symbolica.PatternRestriction:
Create a pattern restriction that tests the type of the atom.
Examples
>>> from symbolica import Expression, AtomType
>>> x, x_ = Expression.vars('x', 'x_')
>>> f = Expression.fun("f")
>>> e = f(x)*f(2)*f(f(3))
>>> e = e.replace_all(f(x_), 1, x_.req_type(AtomType.Num))
>>> print(e)
Yields f(x)*f(1)
.
def req_lit (self ) -> symbolica.symbolica.PatternRestriction:
Create a pattern restriction that treats the wildcard as a literal variable, so that it only matches to itself.
def req ( self, filter_fn: Callable[[symbolica.symbolica.Expression], bool] ) -> symbolica.symbolica.PatternRestriction:
Create a new pattern restriction that calls the function filter_fn
with the matched atom that should return a boolean. If true, the pattern matches.
Examples
>>> from symbolica import Expression
>>> x_ = Expression.var('x_')
>>> f = Expression.fun("f")
>>> e = f(1)*f(2)*f(3)
>>> e = e.replace_all(f(x_), 1, x_.req(lambda m: m == 2 or m == 3))
def req_cmp ( self, other: symbolica.symbolica.Expression | int, cmp_fn: Callable[[symbolica.symbolica.Expression, symbolica.symbolica.Expression], bool] ) -> symbolica.symbolica.PatternRestriction:
Create a new pattern restriction that calls the function cmp_fn
with another the matched atom and the match atom of the other
wildcard that should return a boolean. If true, the pattern matches.
Examples
>>> from symbolica import Expression
>>> x_, y_ = Expression.vars('x_', 'y_')
>>> f = Expression.fun("f")
>>> e = f(1)*f(2)*f(3)
>>> e = e.replace_all(f(x_)*f(y_), 1, x_.req_cmp(y_, lambda m1, m2: m1 + m2 == 4))
def map ( self, transformations: symbolica.symbolica.Transformer ) -> symbolica.symbolica.Expression:
Map the transformations to every term in the expression. The execution happen in parallel.
Examples
>>> x, x_ = Expression.vars('x', 'x_')
>>> e = (1+x)**2
>>> r = e.map(Transformer().expand().replace_all(x, 6))
>>> print(r)
def set_coefficient_ring ( self, vars: Sequence[symbolica.symbolica.Expression] ) -> symbolica.symbolica.Expression:
Set the coefficient ring to contain the variables in the vars
list. This will move all variables into a rational polynomial function.
Parameters
vars : List[Expression] A list of variables
def derivative ( self, x: symbolica.symbolica.Expression ) -> symbolica.symbolica.Expression:
Derive the expression w.r.t the variable x
.
def to_polynomial ( self, vars: Optional[Sequence[ symbolica.symbolica.Expression]] = None ) -> symbolica.symbolica.Polynomial:
Convert the expression to a polynomial, optionally, with the variables and the ordering specified in vars
.
def to_rational_polynomial ( self, vars: Optional[Sequence[ symbolica.symbolica.Expression]] = None ) -> symbolica.symbolica.RationalPolynomial:
Convert the expression to a rational polynomial, optionally, with the variables and the ordering specified in vars
. The latter is useful if it is known in advance that more variables may be added in the future to the rational polynomial through composition with other rational polynomials.
Examples
>>> a = Expression.parse('(1 + 3*x1 + 5*x2 + 7*x3 + 9*x4 + 11*x5 + 13*x6 + 15*x7)^2 - 1').to_rational_polynomial()
>>> print(a)
def to_rational_polynomial_small_exponent ( self, vars: Optional[Sequence[ symbolica.symbolica.Expression]] = None ) -> symbolica.symbolica.RationalPolynomial:
Similar to [PythonExpression::to_rational_polynomial()], but the power of each variable limited to 255.
def match ( self, lhs: symbolica.symbolica.Transformer | symbolica.symbolica.Expression | int, cond: Optional[symbolica.symbolica. PatternRestriction] = None ) -> symbolica.symbolica.MatchIterator:
Return an iterator over the pattern self
matching to lhs
. Restrictions on pattern can be supplied through cond
.
Examples
>>> x, x_ = Expression.vars('x','x_')
>>> f = Expression.fun('f')
>>> e = f(x)*f(1)*f(2)*f(3)
>>> for match in e.match(f(x_)):
>>> for map in match:
>>> print(map[0],'=', map[1])
def replace ( self, lhs: symbolica.symbolica.Transformer | symbolica.symbolica.Expression | int, rhs: symbolica.symbolica.Transformer | symbolica.symbolica.Expression | int, cond: Optional[symbolica.symbolica. PatternRestriction] = None ) -> symbolica.symbolica.ReplaceIterator:
Return an iterator over the replacement of the pattern self
on lhs
by rhs
. Restrictions on pattern can be supplied through cond
.
Examples
>>> from symbolica import Expression
>>> x_ = Expression.var('x_')
>>> f = Expression.fun('f')
>>> e = f(1)*f(2)*f(3)
>>> for r in e.replace(f(x_), f(x_ + 1)):
>>> print(r)
Yields:
f(2)*f(2)*f(3)
f(1)*f(3)*f(3)
f(1)*f(2)*f(4)
def replace_all ( self, lhs: symbolica.symbolica.Transformer | symbolica.symbolica.Expression | int, rhs: symbolica.symbolica.Transformer | symbolica.symbolica.Expression | int, cond: Optional[symbolica.symbolica. PatternRestriction] = None ) -> symbolica.symbolica.Expression:
Replace all patterns matching the left-hand side lhs
by the right-hand side rhs
. Restrictions on pattern can be supplied through cond
.
Examples
>>> x, w1_, w2_ = Expression.vars('x','w1_','w2_')
>>> f = Expression.fun('f')
>>> e = f(3,x)
>>> r = e.replace_all(f(w1_,w2_), f(w1_ - 1, w2_**2), (w1_ >= 1) & w2_.is_var())
>>> print(r)
class Function:
A function class for python that constructs an Expression
when called with arguments. This allows to write:
f = Expression.fun("f")
e = f(1,2,3)
class Transformer:
Operations that transform an expression.
def derivative ( self, x: symbolica.symbolica.Transformer | symbolica.symbolica.Expression ) -> symbolica.symbolica.Transformer:
Create a transformer that derives self
w.r.t the variable x
.
def replace_all ( self, pat: symbolica.symbolica.Transformer | symbolica.symbolica.Expression | int, rhs: symbolica.symbolica.Transformer | symbolica.symbolica.Expression | int, cond: Optional[symbolica.symbolica. PatternRestriction] = None ) -> symbolica.symbolica.Transformer:
Create a transformer that replaces all patterns matching the left-hand side self
by the right-hand side rhs
. Restrictions on pattern can be supplied through cond
.
Examples
>>> x, w1_, w2_ = Expression.vars('x','w1_','w2_')
>>> f = Expression.fun('f')
>>> e = f(3,x)
>>> r = e.transform().replace_all(f(w1_,w2_), f(w1_ - 1, w2_**2), (w1_ >= 1) & w2_.is_var())
>>> print(r)
class Polynomial:
def parse (_cls, input: str, vars: List[str] ) -> symbolica.symbolica.Polynomial:
Parse a polynomial with rational coefficients from a string. The input must be written in an expanded format and a list of all the variables must be provided.
If these requirements are too strict, use Expression.to_polynomial()
or RationalPolynomial.parse()
instead.
Examples
>>> e = Polynomial.parse('3/4*x^2+y+y*4', ['x', 'y'])
Raises
ValueError If the input is not a valid Symbolica polynomial.
def to_integer_polynomial (self ) -> symbolica.symbolica.IntegerPolynomial:
Convert the polynomial to a polynomial with integer coefficients, if possible.
def quot_rem ( self, rhs: symbolica.symbolica.Polynomial ) -> symbolica.symbolica.Polynomial:
Divide self
by rhs
, returning the quotient and remainder.
def gcd ( self, rhs: symbolica.symbolica.Polynomial ) -> symbolica.symbolica.Polynomial:
Compute the greatest common divisor (GCD) of two polynomials.
class IntegerPolynomial:
def parse (_cls, input: str, vars: List[str] ) -> symbolica.symbolica.Polynomial:
Parse a polynomial with integer coefficients from a string. The input must be written in an expanded format and a list of all the variables must be provided.
If these requirements are too strict, use Expression.to_polynomial()
or RationalPolynomial.parse()
instead.
Examples
>>> e = Polynomial.parse('3*x^2+y+y*4', ['x', 'y'])
Raises
ValueError If the input is not a valid Symbolica polynomial.
def quot_rem ( self, rhs: symbolica.symbolica.Polynomial ) -> symbolica.symbolica.Polynomial:
Divide self
by rhs
, returning the quotient and remainder.
def gcd ( self, rhs: symbolica.symbolica.IntegerPolynomial ) -> symbolica.symbolica.IntegerPolynomial:
Compute the greatest common divisor (GCD) of two polynomials.
class RationalPolynomial:
A Symbolica rational polynomial.
RationalPolynomial ( den: symbolica.symbolica.Polynomial )
def parse ( _cls, input: str, vars: List[str] ) -> symbolica.symbolica.RationalPolynomial:
Parse a rational polynomial from a string. The list of all the variables must be provided.
If this requirements is too strict, use Expression.to_polynomial()
instead.
Examples
>>> e = Polynomial.parse('3/4*x^2+y+y*4', ['x', 'y'])
Raises
ValueError If the input is not a valid Symbolica rational polynomial.
def gcd ( self, rhs: symbolica.symbolica.RationalPolynomial ) -> symbolica.symbolica.RationalPolynomial:
Compute the greatest common divisor (GCD) of two rational polynomials.
class RationalPolynomialSmallExponent:
A Symbolica rational polynomial with variable powers limited to 255.
def parse ( _cls, input: str, vars: List[str] ) -> symbolica.symbolica.RationalPolynomial:
Parse a rational polynomial from a string. The list of all the variables must be provided.
If this requirements is too strict, use Expression.to_polynomial()
instead.
Examples
>>> e = Polynomial.parse('3/4*x^2+y+y*4', ['x', 'y'])
Raises
ValueError If the input is not a valid Symbolica rational polynomial.
def gcd ( self, rhs: symbolica.symbolica.RationalPolynomialSmallExponent ) -> symbolica.symbolica.RationalPolynomialSmallExponent:
Compute the greatest common divisor (GCD) of two rational polynomials.
class NumericalIntegrator:
def continuous ( n_dims: int, n_bins: int = 128, min_samples_for_update: int = 100, bin_number_evolution: List[int] = None, train_on_avg: bool = False ) -> symbolica.symbolica.NumericalIntegrator:
Create a new continuous grid for the numerical integrator.
def discrete ( bins: List[Optional[ symbolica.symbolica.NumericalIntegrator]], max_prob_ratio: float = 100.0, train_on_avg: bool = False ) -> symbolica.symbolica.NumericalIntegrator:
Create a new discrete grid for the numerical integrator. Each bin can have a sub-grid.
Examples
>>> def integrand(samples: list[Sample]):
>>> res = []
>>> for sample in samples:
>>> if sample.d[0] == 0:
>>> res.append(sample.c[0]**2)
>>> else:
>>> res.append(sample.c[0]**1/2)
>>> return res
>>>
>>> integrator = NumericalIntegrator.discrete(
>>> [NumericalIntegrator.continuous(1), NumericalIntegrator.continuous(1)])
>>> integrator.integrate(integrand, True, 10, 10000)
def sample (self, num_samples: int ) -> List[symbolica.symbolica.Sample]:
Sample num_samples
points from the grid.
def add_training_samples (self, samples: List[symbolica.symbolica.Sample], evals: List[float]):
Add the samples and their corresponding function evaluations to the grid. Call update
after to update the grid and to obtain the new expected value for the integral.
def update (self, learning_rate: float ) -> Tuple[float, float, float]:
Update the grid using the learning_rate
.
Examples
>>> from symbolica import NumericalIntegrator, Sample
>>>
>>> def integrand(samples: list[Sample]):
>>> res = []
>>> for sample in samples:
>>> res.append(sample.c[0]**2+sample.c[1]**2)
>>> return res
>>>
>>> integrator = NumericalIntegrator.continuous(2)
>>> for i in range(10):
>>> samples = integrator.sample(10000 + i * 1000)
>>> res = integrand(samples)
>>> integrator.add_training_samples(samples, res)
>>> avg, err, chi_sq = integrator.update(1.5)
>>> print('Iteration {}: {:.6} +- {:.6}, chi={:.6}'.format(i+1, avg, err, chi_sq))
def integrate ( self, integrand: Callable[[List[symbolica.symbolica.Sample ]], List[float]], max_n_iter: int = 10000000, min_error: float = 0.01, n_samples_per_iter: int = 10000, show_stats: bool = True ) -> Tuple[float, float, float]:
Integrate the function integrand
that maps a list of Sample
s to a list of float
s. The return value is the average, the statistical error, and chi-squared of the integral.
With show_stats=True
, intermediate statistics will be printed. max_n_iter
determines the number of iterations and n_samples_per_iter
determine the number of samples per iteration. This is the same amount of samples that the integrand function will be called with.
For more flexibility, use sample
, add_training_samples
and update
. See update
for an example.
Examples
>>> from symbolica import NumericalIntegrator, Sample
>>>
>>> def integrand(samples: list[Sample]):
>>> res = []
>>> for sample in samples:
>>> res.append(sample.c[0]**2+sample.c[1]**2)
>>> return res
>>>
>>> avg, err = NumericalIntegrator.continuous(2).integrate(integrand, True, 10, 100000)
>>> print('Result: {} +- {}'.format(avg, err))
class Sample:
class AtomType:
Specifies the type of the atom.
Num = AtomType.Num
Var = AtomType.Var
Fn = AtomType.Fn
Add = AtomType.Add
Mul = AtomType.Mul
Pow = AtomType.Pow
class AtomTree:
A Python representation of a Symbolica expression. The type of the atom is provided in atom_type
.
The head
contains the string representation of:
-
a number if the type is
Num
-
the variable if the type is
Var
-
the function name if the type is
Fn
-
otherwise it is
None
.
The tail contains the child atoms:
-
the summand for type
Add
-
the factors for type
Mul
-
the base and exponent for type
Pow
-
the function arguments for type
Fn
def set_license_key (key: str) -> None:
Set the Symbolica license key for this computer. Can only be called before calling any other Symbolica functions.
def request_hobbyist_license (name: str, email: str ) -> None:
Request a key for non-professional use for the user name
, that will be sent to the e-mail address email
.
def request_trial_license (name: str, email: str, company: str) -> None:
Request a key for a trial license for the user name
working at company
, that will be sent to the e-mail address email
.