Symbolica 3.0 expands exact equation solving and algebraic-number support, introduces precision-aware Python numerical scalars, and improves polynomial arithmetic and numerical evaluation. This overview covers changes since Symbolica 2.2, including the bundled Numerica 3.0 update.
For changes to existing code, see the migration guide.
Exact algebra and solving
- Added exact polynomial-system solving with parameters and solution families.
Expression.solve()returns aSolutionSetcontaining variable assignments, free variables, validity conditions, and complete or generic coverage. Solving supports complex, real, rational, and integer domains; unsupported problems raise an error. The oldsolve_linear_system()entry point was removed. - Added canonical algebraic roots, certified root embeddings, and algebraic contexts for combining generators. Algebraic coefficients can be retained through polynomial conversion and factorization, including factorization in a specified algebraic extension.
- Extended partial fractions to multiple variables with
expr.apart(x, y)and automatic variable selection withexpr.apart(). - Improved polynomial multiplication, homogeneous multiplication, modular GCD reconstruction, factor reconstruction, resultants, and Gröbner-basis reduction. Polynomial storage is more compact, and coefficient domains can supply specialized arithmetic kernels.
- Unified checked polynomial division and improved failure handling for non-exact quotients. Fixed rational-polynomial constants, variable contexts, and arithmetic edge cases; derivatives cancel common factors, and powers use binary exponentiation.
Nonlinear systems with parameters
Solve the coupled system
\[ x^2 + y^2 = a, \qquad xy = b \]
for \(x\) and \(y\), keeping \(a\) and \(b\) as symbolic parameters. Symbols omitted from the unknowns list are treated as parameters automatically:
from symbolica import Expression, S
x, y, a, b = S("x", "y", "a", "b")
solutions = Expression.solve([
(x**2 + y**2).eq(a),
(x*y).eq(b),
], [x, y])The result contains four exact solution branches:
\[ \begin{aligned} t_k &= \operatorname{root}(t^4-at^2+b^2,\,k), && k=0,1,2,3, \\ (x,y) &= \left(\frac{at_k-t_k^3}{b},\;t_k\right). \end{aligned} \]
The new root object keeps the answer compact and exact, even with symbolic parameters. Symbolica also returns the conditions under which these branches cover all solutions. Here they simplify to
\[ b\ne 0, \qquad a^2\ne 4b^2. \]
Substituting parameter values also simplifies the roots. For \(a=5\) and \(b=2\), the four branches become
\[ \{(1,2),\;(2,1),\;(-1,-2),\;(-2,-1)\}. \]
Exceptional parameter values can have solutions too. Solving the original system at \(a=5\), \(b=0\) gives
\[ \{(\sqrt{5},0),\;(-\sqrt{5},0),\;(0,\sqrt{5}),\;(0,-\sqrt{5})\}. \]
Solutions are complex by default. Pass domain=Reals to request real solutions. The migration guide explains how to work with solution branches and their validity conditions.
Algebraic roots
The new root object represents an exact selected root of a polynomial. It can simplify automatically, appear in symbolic expressions, and be evaluated at arbitrary precision. In Python, polynomial.root(index, variable=x) selects a root by its zero-based index in Symbolica’s canonical ordering.
Automatic simplification
Root construction simplifies the defining polynomial and returns a simpler expression when possible. For example, the roots of \((x-3)(x^2-2)\) become radicals or integers immediately:
from symbolica import S
x = S("x")
polynomial = (x - 3) * (x**2 - 2)
roots = [polynomial.root(k) for k in range(3)]This immediately produces
\[ \left[-\sqrt{2},\;\sqrt{2},\;3\right]. \]
When a root remains in polynomial form, it is still an exact algebraic number and can be evaluated at the requested precision:
alpha = (x**3 - x - 1).root(0)
value = alpha.evaluate({}, decimal_digit_precision=80)The exact result and its numerical value, shown here to ten decimal places, are
\[ \begin{aligned} \alpha &= \operatorname{root}(\xi^3-\xi-1,\,0), \\ \alpha &\approx -0.6623589786 - 0.5622795121\,i. \end{aligned} \]
The canonical variable \(\xi\) is bound inside the root object; no value for it is needed during evaluation.
Algebraic-number coefficients
The defining polynomial can itself contain algebraic numbers. For example:
from symbolica import N, S
x = S("x")
sqrt2 = N(2).sqrt()
polynomial = x**2 - (1 + sqrt2)*x + sqrt2
roots = [polynomial.root(k, variable=x) for k in range(2)]Symbolica simplifies the roots exactly:
\[ x^2-(1+\sqrt{2})x+\sqrt{2}=0 \qquad\Longrightarrow\qquad \left[1,\;\sqrt{2}\right]. \]
More general roots can be converted to a defining polynomial over the rationals:
beta = (x**3 - sqrt2*x - 1).root(2, variable=x)The result is
\[ \begin{aligned} \beta &= \operatorname{root}(\xi^6-2\xi^3-2\xi^2+1,\,5) \\ &\approx 1.4504054433. \end{aligned} \]
It is the same selected root of \(x^3-\sqrt{2}x-1\). Symbolica preserves that choice while changing the defining polynomial, so the root index can change during normalization.
Expressions and pattern matching
- Python
==and!=now return Booleans. Use.eq()and.ne()to construct deferred conditions; ordered comparisons also construct conditions. Unknown conditions evaluate toNone. - Mathematical property queries distinguish a proven false result from an unknown one. Python’s
is_real(),is_integer(),is_scalar(),is_positive(), andis_nonnegative()returnTrue,False, orNone. - Match callbacks use
True,False, andNonefor accept, reject, and undecidable. Matching levels now use separatemin_levelandmax_levelbounds in place oflevel_range. - Added the
Flatfunction attribute (is_flat=Truein Python), which flattens nested calls to the same function, and lookup of existing symbols throughExpression.get()in Python andSymbol::get()in Rust. - Extended expression indexing and pruned impossible pattern matches earlier.
- Series coefficient access distinguishes known zero coefficients from terms outside the computed order.
- Added Python access to further transcendental functions, including reciprocal trigonometric and hyperbolic functions and their inverses.
- Improved implicit multiplication before parentheses, Mathematica built-in parsing, fraction formatting, and canonical strings. Canonical strings bypass custom printers.
- Expression export includes only the state needed by the expression. Import preserves symbol metadata and variable mappings more reliably, and tensor sums retain completed contractions.
Breaking change: antisymmetric function matching
Rules that rely on permuting the arguments of an antisymmetric function must be updated. In 2.2, the matcher considered argument permutations. In 3.0, antisymmetric functions match argument by argument in the order stored in the expression, just like ordinary functions.
Antisymmetry still applies during normalization: f(2, 1) becomes -f(1, 2), and f(1, 1) becomes zero. However, calls containing wildcards retain their argument order, so the position of each wildcard in a pattern now matters. For example, f(w_, 1) does not match f(1, 2); use f(1, w_) to match that stored order.
Review replacements, match iterators, and restrictions that depend on a particular wildcard receiving an argument. If a rule needs several argument orders, express them explicitly and account for the permutation sign in the replacement. See the migration example.
Numerical evaluation
- Exposed Numerica’s immutable
FloatandComplexFloatin Python. Arbitrary- precision evaluation, numerical solving, and high-precision polynomial roots return these scalars. Decimal inputs remain supported. - Added precision-aware arithmetic, elementary functions, constants, formatting, Decimal conversion, and random sampling on the new scalars.
- Added non-inlined sub-evaluators, configurable through
FunctionDefinition(..., inlining="always" | "never" | "auto").get_instructions()now exports an object with dimensions, constants, instructions, and nested function bodies. - Compiled evaluator libraries export their input and output dimensions. Loading reads this metadata, and evaluation validates buffer and batch sizes. Replacing a compiled library at the same path is detected.
- Precision evaluators reject invalid input counts and unsupported precision with Python exceptions. Improved preservation of constant precision, evaluation at integer Bessel orders, and transcendental calls in generated C++.
- Updated the SymJIT dependency to 2.25. Direct Rust expression evaluation now also accepts standard-library
HashMapvalues.
Numerica 3.0
- Integer and floating-point backends can be selected independently:
integer-gmporinteger-malachite, andfloat-mpfrorfloat-astro. GMP integers and MPFR floats remain the defaults. - Redesigned compact integer storage, improved integer factorization, and added faster integer, rational, and finite-field polynomial kernels, including checked division kernels.
- Added certified real and complex interval arithmetic for enclosures and root certification.
- Separated mathematical ordering (
OrderedRing,RealEmbedding) and random sampling (SampleableRing) from general ring operations. Added explicit integer-range sampling and compatible RNG re-exports. - Improved complex arithmetic accuracy, decimal parsing, precision validation, and NaN construction that preserves numeric shape. Corrected zero powers in finite fields.
- Corrected matrix inversion and sparse identity checks, validated dense and sparse matrix structure, and added approximate integer lattice-basis reduction.
- Integration grids validate dimensions, bin counts, and sampling settings. Rust continuous and discrete grid constructors now return
Result.
Builds and licensing
- Symbolica uses Numerica 3.0 and Graphica 3.0. The minimum Rust version remains 1.89.
- Added WebAssembly builds with the
wasmfeature. Native compilation and JIT support are controlled bynative_code_generation, enabled by default. - Introduced the Symbolica Source-Available License 1.0. Numerica remains MIT licensed. See the license information and the license supplied with each package.
- Updated signed offline license keys and moved Rust licensing APIs into
symbolica::license. Added signed library keys for scoped multicore unlocking in Python packages and Rust libraries.