# [Symbolica 2.0: programmable symbols – Symbolica | Modern Computer Algebra](https://symbolica.io/posts/symbolica_2_0_release/)
Symbolica is a high-performance symbolic computation framework for Python and Rust. You can use it to manipulate symbolic expressions and turn them into fast numerical kernels for computing Jacobians, numerical optimization, integration, and much more.
Today marks the 2.0 release of Symbolica, with many exciting new features and improvements. The theme of this release is programmable symbols: more of Symbolica’s behavior can now be customized by the user. This makes it possible to define mathematical objects that simplify, differentiate, expand, print, and evaluate like built-ins.
Since 1.0, Symbolica has accumulated improvements in several directions:
- - a simpler Rust API with more operator overloading and builder-style APIs
- - a symbol registration system, with namespaces, aliases, tags, user data, and custom hooks
- - a redesigned evaluator interface that supports double-float arithmetic and JIT compilation
- - richer output for notebooks and documents, including HTML output, graph and polynomial display, Typst output, colorized printing, and more structural multiline formatting
- - new built-in mathematical functions, including gamma, polylogarithms, Bessel functions, Riemann zeta, and related series/evaluation hooks
See the migration guide to learn more about the changes and how to update your code.
## Better output
Symbolica gained an automatic line-wrapping output mode, with colored brackets, similar to how code is styled. This makes it easier to read large, nested expressions. In notebooks, such as Jupyter or Marimo, the default output is a colorful HTML-mode and you can easily switch to LaTeX mode. Typst output is available now as well.
## Improved Rust API
One of the most visible changes is that ordinary Rust programs need far fewer imports and fewer long type paths. The new prelude collects the common traits, macros, domains, and evaluator types that most users need. Rust ergonomics have also been improved with additional overloads, automatic type conversions, builder patterns, and a call method on symbols:
- - Symbolica 2.0
- - Symbolica 1.0
use symbolica::prelude::*; fn main() { let (x, y, f) = symbol!("x", "y", "f"); let e: Atom = 2 + (x + 1).pow(-2) + f.call((1 + y, y)) / 3; let s = e.series(x, 0, 1).unwrap(); println!("{e}"); // -> 2+1/3*f(1+y,y)+1/(1+x)^2 println!("{s}"); // -> 3+1/3*f(1+y,y)-2*x+𝒪(x^2) }
use symbolica::{ atom::{Atom, AtomCore}, function, symbol, }; fn main() { let (x, y, f) = symbol!("x", "y", "f"); let e = Atom::num(2) + (Atom::var(x) + 1).npow(-2) + function!(f, Atom::num(1) + y, y) / 3; let s = e.series(x, Atom::num(0), 1.into(), true).unwrap(); println!("{e}"); // -> 2+1/3*f(1+y,y)+1/(1+x)^2 println!("{s}"); // -> 3+1/3*f(1+y,y)-2*x+𝒪(x^2) }
Structures used for settings and functions with many arguments now use a builder pattern. For example, the construction of a high-performance numerical evaluator now looks like this:
- - Symbolica 2.0
- - Symbolica 1.0
use symbolica::prelude::*; fn main() -> Result<(), EvaluationError> { let mut evaluator = parse!("x^2 + 2*x + 1 + f(x)") .evaluator(&[parse!("x")]) .add_function(symbol!("f"), vec![symbol!("y")], parse!("cos(y + 1)"))? .horner_iterations(2) .build()? .map_coeff(&|c| c.re.to_f64()); println!("{}", evaluator.evaluate_single(&[3.0])); Ok(()) }
…
Symbolica 2.0: programmable symbols for Python and Rust
https://symbolica.io/posts/symbolica_2_0_release/ Lobsters: https://lobste.rs/s/zpjc05/symbolica_2_0_programmable_symbols_for