Sympp
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
- [Examples](#examples) - [Hello World](#hello-world) - [Operations](#operations) - [Equations](#equations) - [Simplification](#simplification) - [Compiling expressions](#compiling-expressions) - [Benchmarks](#benchmarks) - [Integration](#integration) - [Packages](#packages) - [Build from source](#build-from-source) - [CMake targets](#cmake-targets) - [Other build systems](#other-build-systems) - [Limitations and Roadmap](#limitations-and-roadmap) - [Contributing](#contributing) - [Contributors](#contributors) - [Thanks](#thanks)Examples
For complete examples, see the directory examples.
Hello World
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
Operations
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)
Equations
Work in progress
Simplification
Work in progress
Compiling expressions
Work in progress
Benchmarks
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.
Work in progress
Integration
Packages
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)
Build from source
Dependencies
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 ```bash g++ --version ``` The output should have something like ```console g++-8 (Ubuntu 8.4.0-1ubuntu1~18.04) 8.4.0 ``` If you see a version before GCC-8, update it with ```bash 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: ```bash 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: ```bash 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++`: ```bash update-alternatives --config g++ update-alternatives --config gcc ``` Check your CMake version: ```bash cmake --version ``` If it's older than CMake 3.14, update it with ```bash sudo apt upgrade cmake ``` or download the most recent version from [cmake.org](https://cmake.org/). [Later](#build-the-examples) when running CMake, make sure you are using GCC-8 or higher by appending the following options: ```bash -DCMAKE_C_COMPILER=/usr/bin/gcc-8 -DCMAKE_CXX_COMPILER=/usr/bin/g++-8 ```Instructions: Mac Os/Clang
Check your Clang version: ```bash clang --version ``` The output should have something like ```console 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: ```bash cmake --version ``` If it's older than CMake 3.14, update it with ```bash sudo brew upgrade cmake ``` or download the most recent version from [cmake.org](https://cmake.org/). If the last command fails because you don't have [Homebrew](https://brew.sh) on your computer, you can install it with ```bash /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" ``` or you can follow the instructions in [https://brew.sh](https://brew.sh).Instructions: Windows/MSVC
* Make sure you have a recent version of [Visual Studio](https://visualstudio.microsoft.com) * Download Git from [https://git-scm.com/download/win](https://git-scm.com/download/win) and install it * Download CMake from [https://cmake.org/download/](https://cmake.org/download/) and install itBuild the Examples
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
.
Installing SymPP from Source
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.
Building the packages
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.
CMake targets
Find it as a CMake Package
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>
Use it as a CMake subdirectory
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.
CMake with Automatic Download
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.
Other build systems
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>
Limitations and Roadmap
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
Contributing
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.
Example: CLion
![CLion Settings with Pedantic Mode](/sympp/documentation/images/pedantic_clion.png)Contributors
Alan De Freitas |
Thanks
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