Get Started
Use Symbolica from Python for a fast, notebook-friendly computer algebra system, or from Rust when you want maximum control and performance. The C/C++/Mathematica bindings currently expose fast multivariate polynomial arithmetic.
What language should I use?
Choose Python if you want the shortest path to symbolic manipulation, notebooks, and quick experiments. Choose Rust if you are building new features, tuning data structures, or pushing for the highest performance. Rust gives you the most flexibility, at the cost of more verbose code.
The recommended setup is Visual Studio Code or Zed with:
- Jupyter extension
- Pylance extension
- (optional) GitHub Copilot
With this setup you get inline documentation, auto-completion, and LaTeX/Typst rendering of output.
Live demo
Want to try Symbolica before installing it? Open the Google Colab notebook and run the examples in your browser.
You can edit the code and run it on Google Colab without touching your local machine.
There is also a CERN video tutorial.
Installation
Install Symbolica for Python with pip on all major 64-bit platforms:
pip install symbolicaCheck that the import works:
from symbolica import *If this returns without an import error, you are ready to go.
Use maturin if you want to build the Python package yourself:
git clone https://github.com/benruijl/symbolica.git
cd symbolica
maturin build --releaseThen install the wheel with pip:
pip install target/wheels/symbolica-VERSION.whlWindows source builds
On Windows, build from MSYS2. Install m4, git, gcc, rust, and maturin. When you call maturin, put a vanilla Windows Python installation at the start of your path:
PATH="C:\\Users\\benru\\AppData\\Local\\Programs\\Python\\Python311":$PATH maturin build --releaseAdd Symbolica to your Rust project:
cargo add symbolicaThat is all you need on macOS or Linux. On Windows, use the setup below.
Symbolica uses native C/C++ dependencies. On Windows, pair the Rust GNU target with MSYS2 MinGW64.
1. Install the Rust GNU toolchain. Run in PowerShell:
rustup toolchain install stable-x86_64-pc-windows-gnu
rustup default stable-x86_64-pc-windows-gnu2. Install the MSYS2 MinGW64 tools. Install MSYS2, then open the MSYS2 MinGW x64 terminal and run:
pacman -Syu
pacman -S --needed diffutils m4 make mingw-w64-x86_64-toolchain3. Add MSYS2 to your user PATH. Run in PowerShell (adjusting the path when needed):
$add = @("C:\msys64\mingw64\bin", "C:\msys64\usr\bin")
$current = [Environment]::GetEnvironmentVariable("Path", "User")
$new = (($current -split ";" | Where-Object { $_ }) + $add | Select-Object -Unique) -join ";"
[Environment]::SetEnvironmentVariable("Path", $new, "User")Then close and reopen PowerShell, VS Code, or any terminal.
Build the Symbolica library:
git clone https://github.com/benruijl/symbolica.git
cd symbolica
cargo rustc --release --crate-type=cdylibThis generates a dynamically linked library. Use --crate-type=staticlib to build a static library instead.
Now try the C interface:
test.c
#include <stdio.h>
typedef struct SYMBOLICA* Symbolica;
extern Symbolica *init();
extern void set_vars(Symbolica* symbolica, const char *vars);
extern void set_options(Symbolica *symbolica, const bool input_has_rational_numbers, bool exp_fits_in_u8);
extern char* simplify(Symbolica* symbolica, const char *input, unsigned long long prime, char explicit_rat);
extern void drop(Symbolica *symbolica);
int main() {
char* in = "(x+5)/(x+6) + 35/y";
char* in2 = "(x*y^2*5+5)^2/(2*x+5)+(x+4)/(6*x^2+1)";
Symbolica* s = init();
set_vars(s, "x,y,z");
char* out = simplify(s, in, 0, 1);
printf("%s\n", out);
out = simplify(s, in2, 5, 1);
printf("%s\n", out);
drop(s);
return 0;
}Compile it with dynamic linking:
gcc -O3 test.c -L target/release -lsymbolica -o testor static linking:
gcc -O3 test.c -L target/release -l:libsymbolica.a -lm -o testtest.cpp
#include <iostream>
typedef struct SYMBOLICA *Symbolica;
extern "C"
{
extern Symbolica *init();
extern void set_vars(Symbolica *symbolica, const char *vars);
extern void set_options(Symbolica *symbolica, char input_has_rational_numbers, char exp_fits_in_u8);
extern const char *simplify(Symbolica *symbolica, const char *input, unsigned long long prime, char explicit_rat);
extern void drop(Symbolica *symbolica);
}
int main()
{
const char *in = "(x+5)/(x+6) + 35/y";
const char *in2 = "(x*y^2*5+5)^2/(2*x+5)+(x+4)/(6*x^2+1)";
Symbolica *s = init();
set_vars(s, "x,y,z");
const char *out = simplify(s, in, 0ull, 0);
std::cout << out << std::endl;
out = simplify(s, in2, 5ull, 0);
std::cout << out << std::endl;
drop(s);
return 0;
}Compile it with dynamic linking:
g++ -O3 test.cpp -L target/release -lsymbolica -o testor static linking:
g++ -O3 test.cpp -L target/release -l:libsymbolica.a -lm -o testRunning ./test should print the following. For dynamic linking, use LD_LIBRARY_PATH=target/release ./test.
(210+5*y+35*x+x*y)/(6*y+x*y)
(-1+x)/(1+x^2)
License
Choose the license path that matches your use.
Use this path if you use Symbolica commercially, or if you need unrestricted cores. You can buy a professional license or request a free 30-day trial.
Request a trial key
from symbolica import *
request_trial_license('NAME', 'EMAIL', 'ORGANIZATION')use symbolica::LicenseManager;
fn main() {
LicenseManager::request_trial_license("Name", "Email", "Organization").unwrap();
}The license key is emailed immediately. If the trial expires and you need more time, contact license@symbolica.io.
Generate a personal key
If your organization has an active Symbolica license, use the organization’s master key to generate a personal key:
from symbolica import *
request_sublicense('Name', 'Email', 'Organization', 'MASTER_KEY')use symbolica::LicenseManager;
fn main() {
LicenseManager::request_sublicense("Name", "Email", "Organization", "MASTER_KEY").unwrap();
}Use this path if you are non-employed and non-affiliated, for example as a hobbyist or most students1. You can request a free annual hobbyist key:
from symbolica import *
request_hobbyist_license('YOUR_NAME', 'YOUR_EMAIL')use symbolica::LicenseManager;
fn main() {
LicenseManager::request_hobbyist_license("Name", "Email").unwrap();
}The license key is emailed immediately.
Use this path if your work is non-commercial and you do not need unrestricted cores. This includes many academic users2.
Restricted mode is free and does not require registration. It is limited to one instance and one core per device.
Symbolica is optimized for strong single-core performance, so restricted mode is still useful for real-world tasks.
Commercial users cannot use restricted mode for commercial work; use the professional license path instead.
To hide the startup banner in restricted mode, set the environment variable:
SYMBOLICA_HIDE_BANNER=1Updating the key
If your key was extended or lost, have it resent:
from symbolica import *
get_license_key('YOUR_EMAIL')use symbolica::LicenseManager;
fn main() {
LicenseManager::get_license_key("Email").unwrap();
}Setting the license key
To use a license key, set the SYMBOLICA_LICENSE environment variable:
SYMBOLICA_LICENSE=abe2d4f1-3251-5377-b175-ca1912beb982Alternatively, set it at the start of your program before calling any other Symbolica functions:
from symbolica import *
set_license_key("abe2c4f1-3351-5477-b075-cb1962beb982")
x = S('x')Make sure to call set_license_key before importing any community modules:
from symbolica import *
set_license_key("abe2c4f1-3351-5477-b075-cb1962beb982")
from symbolica.community.spenso import * # noqa: E402use symbolica::{LicenseManager, atom::{Atom, AtomCore}};
fn main() {
LicenseManager::set_license_key("abe2c4f1-3351-5477-b075-cb1962beb982").unwrap();
let x = parse!("x");
}extern int set_license_key(const char *key);
int main() {
set_license_key("abe2c4f1-3351-5477-b075-cb1962beb982");
}License keys also work offline.
Examples
Start with a simple expansion:
from symbolica import *
x = S('x')
e = (1+x)**2
r = e.expand()
print(r)use symbolica::{atom::AtomCore, parse};
fn main() {
let input = parse!("(1+x)^3");
let o = input.expand();
println!("> Expansion of {}: {}", input, o);
}Output
3*x+3*x^2+x^3+1
Pattern matching
Pattern matching is the main way to rewrite expressions. Variables ending with _ are wildcards and match any subexpression. Here we match f(1,2,y_) and replace it with f(1,2,y_+1).
from symbolica import *
f, x, x_ = S('f', 'x','x_')
e = f(1,2,x) + f(1,2,3)
r = e.replace(f(1,2,x_), f(1,2,x_+1))
print(r)use symbolica::{atom::AtomCore, parse};
fn main() {
let expr = parse!("f(1,2,x) + f(1,2,3)");
let pat = parse!("f(1,2,y_)");
let rhs = parse!("f(1,2,y_+1)");
let out = expr.replace(pat).with(rhs);
println!("{}", out);
}Applied to f(1,2,x)+f(1,2,3), this gives:
f(1,2,x+1) + f(1,2,4)
To learn more about pattern matching, see Pattern matching.
Rational arithmetic
Rational arithmetic is one of Symbolica’s strengths, with performance competitive with Mathematica, Maple, FORM, Fermat, and other computer algebra systems. Convert an expression to a rational polynomial:
from symbolica import Expression
x, y = Expression.symbol('x','y')
p = Expression.parse('(x*y^2*5+5)^2/(2*x+5)+(x+4)/(6*x^2+1)').to_rational_polynomial()
print(p)use symbolica::{
atom::Atom,
rings::{
integer::IntegerRing, rational::RationalField, rational_polynomial::RationalPolynomial,
},
};
fn main() {
let expr = parse!("(x*y^2*5+5)^2/(2*x+5)+(x+4)/(6*x^2+1)");
let rat: RationalPolynomial<IntegerRing, u8> = expr
.to_rational_polynomial(
RationalField::new(),
IntegerRing::new(),
None,
);
println!("{}", rat);
}The header is the same as in the installation instructions, so it is omitted here.
int main()
{
const char *in = "(x*y^2*5+5)^2/(2*x+5)+(x+4)/(6*x^2+1)";
Symbolica *s = init();
set_vars(s, "x,y");
const char *out = simplify(s, in, 0ull, 0);
std::cout << out << std::endl;
drop(s);
return 0;
}Output
(45+13*x+50*x*y^2+152*x^2+25*x^2*y^4+300*x^3*y^2+150*x^4*y^4)/(5+2*x+30*x^2+12*x^3)
API reference
Use an IDE such as Visual Studio Code to get inline documentation and auto-completion:

The language-specific API references are here:
Learn more
Good next steps: