Get Started

Symbolica can be used as a library in Rust and Python. The C/C++/Mathematica bindings currently allow for fast multivariate polynomial arithmetic only.

What language should I use?

The Python API makes the most sense for beginners, as it is convenient to use. The Rust library makes sense for advanced users who want to develop new features or need fine-grained control over their data structures. Rust will give the highest performance, and the greatest flexibility. This comes at the cost of more verbosity.

The recommended setup is Visual Studio Code with:

  • Jupyter extension
  • Pylance extension
  • (optional) Github Copilot

With this setup you will get inline documentation, auto-completion and LaTeX rendering of output. For example:

A demo of Symbolica

Live demo

A live demo of Symbolica in a Python Jupyter notebook is available on Google Colab.

You can easily make modifications to the code and run it on the Google Colab servers without any local installation.

There is also a video tutorial available, held at CERN.

Installation

Symbolica can be installed for Python >3.5 using pip on all major 64-bit platforms:

pip install symbolica

The installation will likely be instantaneous, but on some systems it requires a manual compilation of Symbolica that may take several minutes.

Manual installation

Alternatively, one can build and install the Python module of Symbolica using maturin:

git clone https://github.com/benruijl/symbolica.git
cd symbolica
maturin build --release

Then Symbolica can be installed using pip:

pip install target/wheels/symbolica-VERSION.whl

On Windows, the compilation has to take place in MSYS2. Install m4, git, gcc, rust, and maturin. When calling maturin make sure to add a vanilla Windows Python installation to the start of your path:

PATH="C:\\Users\\benru\\AppData\\Local\\Programs\\Python\\Python311":$PATH maturin build --release

Testing

To see if it works, open a Python session and try:

from symbolica import *

If you get no import error, the installation was successful.

If you are using Symbolica as a library in Rust, simply include it in the Cargo.toml:

[dependencies]
symbolica = "0.12"

To use the latest development version, import it from git:

[dependencies]
symbolica = { git = "https://github.com/benruijl/symbolica.git" }

You can try some Rust examples in the examples folder.

Apart from the documentation on this website, the Rust documentation can also be accessed on docs.rs.

Download and compile Symbolica with:

git clone https://github.com/benruijl/symbolica.git
cd symbolica
cargo rustc --release --crate-type=cdylib

to generate a dynamically linked library. Use --crate-type=staticlib to generate a static one.

If you use the library statically, the feature --features=faster_alloc can be added to the compilation command for extra performance.

Now try the following example C code:

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;
}

It can be compiled with dynamic linking:

gcc -O3 test.c -L target/release -lsymbolica -o test

or with static linking:

gcc -O3 test.c -L target/release -l:libsymbolica.a -lm -o test
test.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;
}

It can be compiled with dynamic linking:

g++ -O3  test.cpp -L target/release -lsymbolica -o test

or with static linking:

g++ -O3  test.cpp -L target/release -l:libsymbolica.a -lm -o test

Running the file ./test (or LD_LIBRARY_PATH=target/release ./test for the dynamically linked compilation) should give:

(210+5*y+35*x+x*y)/(6*y+x*y)
(-1+x)/(1+x^2)

License

If you run Symbolica without a valid license key, you are running in restricted mode. In this mode Symbolica is limited to one instance and one core per device. Non-commercial users1 (for example hobbyists and most academics) are allowed to run in this mode for free and can remove the banner by setting the environment variable

SYMBOLICA_HIDE_BANNER = 1

Symbolica has been optimized to give you excellent single-core performance.

Professional users

Professional users that want to run Symbolica on an unrestricted number of cores can acquire a professional license or sign up for a free 30-day trial, by providing their credentials in the following command:

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 will be emailed to you immediately. If the trial expires and you want to keep trying Symbolica, you can reach out to for an extension.

Personal key

If your organization has an active Symbolica license, you can use the organization’s master license key to generate a personal license 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();
}

Non-professional users

Non-employed and non-affiliated users (for example hobbyists and most students2) can get a free annual hobbyist license key by providing their name and email address in following command:

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 will be emailed to you immediately.

Updating the key

If you already have a key, but require an updated one (for example because of an extension of the license) or because you lost it, you can 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

If you have a license key, simply provide it in the environment variable SYMBOLICA_LICENSE. For example:

SYMBOLICA_LICENSE=abe2d4f1-3251-5377-b175-ca1912beb982

or provide 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 = Expression.symbol('x')
use symbolica::{LicenseManager};

fn main() {
    LicenseManager::set_license_key("abe2c4f1-3351-5477-b075-cb1962beb982").unwrap();
    let x = Atom::parse("x");
}
extern int set_license_key(const char *key);

int main() {
    set_license_key("abe2c4f1-3351-5477-b075-cb1962beb982");
}

Your license key can also be used without an active internet connection.

Examples

In the following example we create a Symbolica expression (1+x)^3, and expand it:

from symbolica import Expression
x = Expression.symbol('x')
e = (1+x)**2
r = e.expand()
print(r)
use symbolica::atom::Atom;

fn main() {
    let input = Atom::parse("(1+x)^3").unwrap();
    let o = input.expand();

    println!("> Expansion of {}: {}", input, o);
}

which yields 3*x+3*x^2+x^3+1.

Pattern matching

Pattern matching and replacements are an important part of symbolica manipulation. Variables ending with a _ are wildcards and can match any subexpression. In the following example we try to match the pattern f(1,2,y_) and replace it by f(1,2,y_+1).

from symbolica import Expression
x, x_ = Expression.symbol('x','x_')
f = Expression.symbol('f')
e = f(1,2,x) + f(1,2,3)
r = e.replace_all(f(1,2,x_), f(1,2,x_+1))
print(r)
use symbolica::{id::Pattern, atom::Atom};

fn main() -> Result<(), String> {
    let expr = Atom::parse(" f(1,2,x) + f(1,2,3)")?;
    let pat = Pattern::parse("f(1,2,y_)")?;
    let rhs = Pattern::parse("f(1,2,y_+1)")?;

    let out = pat.replace_all(expr.as_view(), &rhs, None, None);

    println!("{}", out);
    Ok(())
}

Applying the pattern to the expression f(1,2,x)+f(1,2,3) we get:

f(1,2,x+1) + f(1,2,4)

To learn more about pattern matching, see Pattern matching.

Rational arithmetic

Symbolica is world-class in rational arithmetic, outperforming Mathematica, Maple, Form, Fermat, and other computer algebra packages. Simply 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() -> Result<(), String> {
    let expr = Atom::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);
    Ok(())
}

The header is omitted, as it is the same as in the installation instructions.

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;
}

which yields

(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

It is advised to use an IDE such as Visual Studio Code to make use of in-line documentation and auto-completion:

A demo of Symbolica

A complete overview of the language-specific APIs can be found below:

For the Python API a full overview of all the functions and its documentation is provided here.

Rust documentation can be read at docs.rs. Also make sure to check out the examples.

Learn more

There are several places where you can learn more about Symbolica.

  • Browse the guide to learn more about Symbolica features.
  • Follow the project on Github to see all changes.
  • Read developer and Rust documentation on docs.rs.
  • Follow the development and discussions on Zulip and Discord.
  • Check out the Blog to learn about computer algebra and the inner workings of Symbolica.

Footnotes

  1. Please reach out if you are not sure if you qualify as a non-commercial user.↩︎

  2. If you publish papers under your university name or with a co-author that has an affiliation, you do not qualify as a non-professional user. Read more here.↩︎