Symbolic computing deals with algorithms that manipulate mathematical expressions. They are useful for mathematical experiments, scientific computation, optimization, improving numerical methods, reducing approximation errors, and as an alternative when numerical analysis fails. However, algebraic manipulations tend to have very low performance, and that makes symbolic computing less attractive to a variety of fields that could otherwise benefit from it. In that context, this project proposes a library for symbolic computing whose symbols can compile themselves. SymPP can numerically evaluate expressions in runtime by 1) generating and compiling the symbolic tree as machine code, 2) concatenating recursive lambdas, or 3) with a depth-first search on the symbol nodes.
Please note that this is a work in progress. See our roadmap to understand some of our plans for the future.
Table of Contents
For complete examples, see the directory examples.
By passing a string literal to a sym
object, we create a symbolic variable:
#include <sympp/sympp.h>
int main() {
using namespace sympp;
using std::cout, std::endl;
sym a("Hello");
sym b("World");
sym c = a + b;
cout << c << endl;
return 0;
}
Instead of trying to somehow immediately evaluate the expression, the result (c
) stores the complete symbolic expression:
Hello+World
Symbols can represent constants, variables, numbers, functions, or complete expressions:
#include <sympp/sympp.h>
int main() {
using namespace sympp;
using std::cout, std::endl;
// Constants
sym A("A",10);
sym n("n",3);
sym pi = constant::pi();
// Variables
sym x1("x_1");
sym x2("x_2");
sym x3("x_3");
// Function terms
sym begin = A * n;
sym term1 = sympp::pow(x1, sym(2)) - A * sympp::cos(2 * pi * x1);
sym term2 = power(x2, sym(2)) - A * cosine(2 * pi * x2);
sym term3 = power(x3, sym(2)) - A * cosine(2 * pi * x3);
// Function
sym rastrigin = begin + term1 + term2 + term3;
cout << rastrigin << endl;
return 0;
}
Output:
A*n+x_1^(2)-A*cos(2*pi*x_1)+x_2^(2)-A*cos(2*pi*x_2)+x_3^(2)-A*cos(2*pi*x_3)
These benchmarks illustrate how we can have significant performance gains by compiling expressions. The compiled expressions not only perform better than the usual symbolic evaluation but also the original unsimplified numeric evaluation.
You can download the binary packages from the CI artifacts or build the library from the source files.
Once the package is installed, link your C++ program to the library and include the directories where you installed SymPP.
Unless you changed the default options, the C++ library is likely to be in /usr/local/
(Linux / Mac OS) or C:/Program Files/
(Windows). The installer will try to find the directory where you usually keep your libraries but that's not always perfect.
If you are using CMake, you can then find SymPP with the usual find_package
command:
find_package(SymPP REQUIRED)
# ...
target_link_libraries(my_target PUBLIC sympp)
CMake should be able to locate the SymPPConfig.cmake
script automatically if you installed the library under /usr/local/
(Linux / Mac OS) or C:/Program Files/
(Windows). Otherwise, you need to include your installation directory in CMAKE_MODULE_PATH
first:
list(APPEND CMAKE_MODULE_PATH put/your/installation/directory/here)
find_package(SymPP REQUIRED)
# ...
target_link_libraries(my_target PUBLIC sympp)
This section lists the dependencies you need before installing SymPP from source. The build script will try to find all these dependencies for you:
- C++17
- CMake 3.14 or higher
- LibTCC (Embedded)
Instructions: Linux/Ubuntu/GCC
Check your GCC version
g++ --version
The output should have something like
g++-8 (Ubuntu 8.4.0-1ubuntu1~18.04) 8.4.0
If you see a version before GCC-8, update it with
sudo apt update
sudo apt install gcc-8
sudo apt install g++-8
To update to any other version, like GCC-9 or GCC-10:
sudo apt install build-essential
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt install g++-10
Once you installed a newer version of GCC, you can link it to update-alternatives
. For instance, if you have GCC-7 and GCC-10, you can link them with:
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 7
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-7 7
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 10
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 10
You can now use update-alternatives
to set you default gcc
and g++
:
update-alternatives --config g++
update-alternatives --config gcc
Check your CMake version:
cmake --version
If it's older than CMake 3.14, update it with
sudo apt upgrade cmake
or download the most recent version from cmake.org.
Later when running CMake, make sure you are using GCC-8 or higher by appending the following options:
-DCMAKE_C_COMPILER=/usr/bin/gcc-8 -DCMAKE_CXX_COMPILER=/usr/bin/g++-8
Instructions: Mac Os/Clang
Check your Clang version:
clang --version
The output should have something like
Apple clang version 11.0.0 (clang-1100.0.33.8)
If you see a version before Clang 11, update XCode in the App Store or update clang with homebrew.
Check your CMake version:
cmake --version
If it's older than CMake 3.14, update it with
sudo brew upgrade cmake
or download the most recent version from cmake.org.
If the last command fails because you don't have Homebrew on your computer, you can install it with
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
or you can follow the instructions in https://brew.sh.
Instructions: Windows/MSVC
- Make sure you have a recent version of Visual Studio
- Download Git from https://git-scm.com/download/win and install it
- Download CMake from https://cmake.org/download/ and install it
This will build the examples in the build/examples
directory:
mkdir build
cmake -version
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O2"
cmake --build . -j 2 --config Release
On windows, replace -O2
with /O2
.
This will install SymPP on your system:
mkdir build
cmake -version
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O2" -DBUILD_EXAMPLES=OFF -DBUILD_TESTS=OFF
cmake --build . -j 2 --config Release
cmake --install .
On windows, replace -O2
with /O2
. You might need sudo
for this last command.
This will create the binary packages you can use to install SymPP on your system:
mkdir build
cmake -version
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O2" -DBUILD_EXAMPLES=OFF -DBUILD_TESTS=OFF
cmake --build . -j 2 --config Release
cmake --install .
cpack .
On windows, replace -O2
with /O2
. You might need sudo
for this last command.
If you have the library installed, you can call
find_package(SymPP)
from your CMake build script.
When creating your executable, link the library to the targets you want:
add_executable(my_target main.cpp)
target_link_libraries(my_target PUBLIC sympp)
Add this header to your source files:
#include <sympp/sympp.h>
You can use SymPP directly in CMake projects without installing it. Check if you have Cmake 3.14+ installed:
cmake -version
Clone the whole project
git clone https://github.com/alandefreitas/sympp/
and add the subdirectory to your CMake project:
add_subdirectory(sympp)
When creating your executable, link the library to the targets you want:
add_executable(my_target main.cpp)
target_link_libraries(my_target PUBLIC sympp)
Add this header to your source files:
#include <sympp/sympp.h>
However, it's always recommended to look for SymPP with find_package
before including it as a subdirectory. Otherwise, we can get ODR errors in larger projects.
Check if you have Cmake 3.14+ installed:
cmake -version
Install CPM.cmake and then:
CPMAddPackage(
NAME SymPP
GITHUB_REPOSITORY alandefreitas/sympp
GIT_TAG origin/master # or whatever tag you want
)
# ...
target_link_libraries(my_target PUBLIC sympp)
Then add this header to your source files:
#include <sympp/sympp.h>
However, it's always recommended to look for SymPP with find_package
before including it as a subdirectory. You can use:
option(CPM_USE_LOCAL_PACKAGES "Try `find_package` before downloading dependencies" ON)
to let CPM.cmake do that for you. Otherwise, we can get ODR errors in larger projects.
If you want to use it in another build system you can either install the library (Section Installing) or you have to somehow rewrite the build script.
If you want to rewrite the build script, your project needs to 1) include the headers and compile all source files in the sources
directory, and 2) link the dependencies described in sources/CMakeLists.txt
.
Then add this header to your source files:
#include <sympp/sympp.h>
Things SymPP needs to improve:
- Lots of tests
- Merge redundant
print
andc_code
functions - More printing formats (inline, code, latex)
- Smarter simplification functions
Things SymPP doesn't do yet:
- Serialization
- Interval arithmetic
- Black-box function lambdas
- Calculus
- Variable integration graphs (VIG)
- Conditional VIGs
- OpenCL
- Matrices
There are many ways in which you can contribute to this library:
- Testing the library in new environments
- Contributing with interesting examples
- Developing new node types
- Finding bugs in general
- Whatever idea seems interesting to you
If contributing with code, please turn the pedantic mode ON (-DBUILD_WITH_PEDANTIC_WARNINGS=ON
), don't forget cppcheck and clang-format.
Alan De Freitas |
We would like to thank the developers of these libraries:
- SymPy: we often use SymPy as a reference for our interface
- SymbolicC++: we used SymbolicC++ as a reference for our polymorphic design
- TinyCC: we use TinyCC to compile expressions to machine code