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 a new feature. Rust will give the highest performance, and the greatest flexibility. This comes at the cost of more verbosity.
Installation
Symbolica can be installed for Python >3.5 using pip
:
pip install symbolica
The installation may take some time, as it may have to compile Symbolica.
Manual installation
Alternatively, one can install Symbolica manually (or compile with maturin). Compile Symbolica with a recent Rust compiler:
git clone https://github.com/benruijl/symbolica.git
cd symbolica
cargo build --release --features python_api
and copy the shared library to your destination location, stripping the leading lib
from the filename:
cp target/release/libsymbolica.so symbolica.so
Note that macOS users may need to add extra flags.
Testing
To see if it works, open a Python session and try:
from symbolica import Expression
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 = { "*" }
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 build --release
If you use the library statically, the feature --features=faster_alloc
can be added to the cargo build
to provide 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)";
* s = init();
Symbolica(s, "x,y,z");
set_varschar* out = simplify(s, in, 0, 1);
("%s\n", out);
printf
= simplify(s, in2, 5, 1);
out ("%s\n", out);
printf
(s);
drop
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)";
*s = init();
Symbolica (s, "x,y,z");
set_varsconst char *out = simplify(s, in, 0ull, 0);
std::cout << out << std::endl;
= simplify(s, in2, 5ull, 0);
out std::cout << out << std::endl;
(s);
drop
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 unregistered mode. In this mode Symbolica is limited to one instance and one core.
Professional users are not allowed to use the unregistered mode and will have to get a professional license or a free trial.
Non-professional users are permitted to use the unregistered mode, but it is also very easy and free to request a hobbyist license by providing your name and e-mail address:
from symbolica import request_hobbyist_license
'YOUR_NAME', 'YOUR_EMAIL') request_hobbyist_license(
use symbolica::LicenseManager;
fn main() {
LicenseManager::request_hobbyist_license("Name", "Email").unwrap();
}
The license key will be e-mailed to you immediately.
If you have a license key, simply provide it in an environment variable SYMBOLICA_LICENSE
, .e.g
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 Expression, Transformer, set_license_key
'abe2c4f1-3851-5177-b075-cb1912beb982')
set_license_key(= Expression.var('x_') x_
use symbolica::{state::State, LicenseManager};
fn main() {
LicenseManager::set_license_key("abe2c4f1-3851-5177-b075-cb1912beb982").unwrap();
let mut _state = State::new();
}
Examples
In the following example we create a Symbolica expression (1+x)^3
, and expand it:
from symbolica import Expression
= Expression.var('x')
x = (1+x)**2
e = e.expand()
r print(r)
use symbolica::{
representations::Atom,
state::{ResettableBuffer, State, Workspace},
};
fn main() {
let mut state = State::new();
let workspace: Workspace = Workspace::default();
let input = Atom::parse("(1+x)^3", &mut state, &workspace).unwrap();
let mut o = Atom::new();
.as_view().expand(&workspace, &state, &mut o);
input
println!(
"> Expansion of {}: {}",
.printer(&state),
input.printer(&state)
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
= Expression.vars('x','y_')
x, y_ = Expression.fun('f')
f = f(1,2,x) + f(1,2,3)
e = e.replace_all(f(1,2,x_), f(1,2,x_+1))
r print(r)
use ahash::HashMap;
use symbolica::{
id::Pattern,
printer::{AtomPrinter, PrintMode},
representations::Atom,
state::{ResettableBuffer, State, Workspace},
};
fn main() {
let mut state = State::new();
let workspace = Workspace::new();
let expr = Atom::parse(" f(1,2,x) + f(1,2,3)", &mut state, &workspace).unwrap();
let pat = Pattern::parse("f(1,2,y_)", &mut state, &workspace).unwrap();
let rhs = Pattern::parse("f(1,2,y_+1)", &mut state, &workspace).unwrap();
let mut out = Atom::new();
.replace_all(
pat.to_view(),
expr&rhs,
&state,
&workspace,
&HashMap::default(),
&mut out,
;
)println!("{}", out.printer(&state));
}
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
= Expression.vars('x','y')
x, y = Expression.parse('(x*y^2*5+5)^2/(2*x+5)+(x+4)/(6*x^2+1)').to_rational_polynomial()
p print(p)
use symbolica::{
printer::{PrintMode, RationalPolynomialPrinter},
representations::Atom,
rings::{
integer::IntegerRing, rational::RationalField, rational_polynomial::RationalPolynomial,
},
state::{State, Workspace},
};
fn main() {
let mut state = State::new();
let workspace = Workspace::new();
let expr = Atom::parse("(x*y^2*5+5)^2/(2*x+5)+(x+4)/(6*x^2+1)", &mut state, &workspace).unwrap();;
let rat: RationalPolynomial<IntegerRing, u8> = expr
.to_view()
.to_rational_polynomial(
&workspace,
&state,
RationalField::new(),
IntegerRing::new(),
None,
).unwrap();
println!(
"{}",
RationalPolynomialPrinter::new(&rat, &state, PrintMode::default())
;
)}
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)";
*s = init();
Symbolica (s, "x,y");
set_varsconst char *out = simplify(s, in, 0ull, 0);
std::cout << out << std::endl;
(s);
drop
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 complete overview of the language-specific APIs can be found below:
Learn more
There are several places where you can learn more about Symbolica.