Repository containing some utility frequently used inside different libraries.
- Bernardo Fichera ([email protected])
- File Manager
- Timer
- Eigen Memory Allocation checker
- Derivative checker
- add memory allocation monitoring (https://en.cppreference.com/w/cpp/types/alignment_of)
- introduce retraction based taylor expansion to check derivative on manifolds
utils-lib is header only library. In order to use it just include the header relative to the utils you intend to use in your project.
In order to read/write from/to a given file create and instance of the FileManager
object and set the path to the file you want to operate on
utils_lib::FileManager file_manager;
file_manager.setFile("path/to/file");
In case you want to write on the file, if either the file or the folder(s) in the path do not exist they will be automatically created. To write on the file call the write
passing the elements you want to write. The utility uses variadic template techniques in order to allow to write onto a file an arbitrary number of elements in sequence. For instance
constexpr int dim = 100;
Eigen::VectorXd x = Eigen::VectorXd::Random(dim), y = Eigen::VectorXd::Random(dim);
file_manager.write("x", x, "y", y);
The above snippet shows how to write the vectors
file_manager.append("x", x, "y", y)
In order to read from file you can just call the read
method specializing the template to the type of object you want to read. In addition you can specify and specific string present in the file from which starting to read as well as an end string where to stop reading. If no end key is specifying the algorithm will stop reading at the first blank line encountered. Sometime after you want to ignore reading a bunch of lines; set the second argument in the read
method to achieve that (read<object_type>(key_start, num_lines_to_ignore, key_end)
). The utility supports methods chaining technique. So in case you want to read from a new file you can set it and read from it in one line.
Eigen::VectorXd x, y;
x = file_manager.setFile("path/to/new/file").read<Eigen::MatrixXd>("x", 2);
y = file_manager.setFile("path/to/new/file").read<Eigen::MatrixXd>("y", 2);
When you specify a key start you want to ignore this line itself and the space after it; therefore the number read_write.cpp
to find out more.
The timer utility measures the time in between the creation and the destruction of the Timer
object. Place the piece of code you want to benchmark within the same scope of the Timer
object. For instance
constexpr int dim = 100;
Eigen::Matrix<double, dim, dim> A = Eigen::Matrix<double, dim, dim>::Random();
Eigen::Matrix<double, dim, 1> x = Eigen::Matrix<double, dim, 1>::Random(), b = Eigen::Matrix<double, dim, 1>::Zero();
{
utils_lib::Timer timer;
for (size_t i = 0; i < dim; i++)
for (size_t j = 0; j < dim; j++)
b(i) += A(i, j) * x(j);
}
{
utils_lib::Timer timer;
b = A * x;
}
As soon as Timer
goes out of scope it will print the duration in time (in us, ms and s). Check the example time_benchmark.cpp
to find out more.
In scenarios where we want to run application in real-time maintaining consistent frequency, runtime memory allocation is an important aspect. This is an utility based on Eigen Linear Algebra Library. It is inspired from this repo. Whenever you need to check if eigen is allocating memory at runtime include the utility header before including Eigen
.
#include <utils_lib/RealtimeChecker.hpp>
#include <Eigen/Core>
Place the code where you want to avoid runtime memory allocation in between the macros ENTERING_REAL_TIME_CRITICAL_CODE
and EXITING_REAL_TIME_CRITICAL_CODE
. For instance
Eigen::MatrixXd a = Eigen::MatrixXd::Random(5, 5), b = Eigen::MatrixXd::Random(5, 5), c = Eigen::MatrixXd::Random(5, 5);
ENTERING_REAL_TIME_CRITICAL_CODE
// no memory allocation
a.noalias() += b * c;
// memory allocation
a += b * c;
EXITING_REAL_TIME_CRITICAL_CODE
The code will go through the first operation while it will crash in the second one where memory allocations happens. Check the example eigen_malloc.cpp
to find out more.
This utility helps in numerically checking derivatives (up to second order). In order to check the gradient, the algorithm simply check that the taylor expansion up to the first derivative
First define your function and the derivative of it.
template <int size>
struct Function {
double operator()(const Eigen::Matrix<double, size, 1>& x) const
{
return x(0) * x(0) * x(0);
}
};
// grad f(x)
template <int size>
struct Gradient {
Eigen::Matrix<double, size, 1> operator()(const Eigen::Matrix<double, size, 1>& x) const
{
return 3 * x * x;
}
};
The utility is fully templated; you have the freedom to define your functions as structures with overloaded ()
operators, as shown above, lambda functions, std::functions
wrapper or raw pointers. Define an instance of the utility (specifying the problem dimension) and then call the checkGradient
method.
constexpr int dim = 1;
utils_lib::DerivativeChecker<long double> checker(dim);
bool grad_is_correct = checker.checkGradient(Function<dim>(), Gradient<dim>());
Check the example check_derivative.cpp
to find out more.
This library depends on Eigen linear algebra library to load data into Eigen vectors/matrices. For various utilities the library depends on Corrade utility library.
Corrade installation:
git clone https://github.com/mosra/corrade.git ([email protected]:mosra/corrade.git)
cd corrade && mkdir build && cmake .. && make && (sudo) make install
Eigen installation:
git clone https://gitlab.com/libeigen/eigen.git ([email protected]:libeigen/eigen.git)
cd eigen && mkdir build && cmake .. && (sudo) make install
In addition, in order to compile the project, install my waf-tools.
Compile and install using waf commands
waf configure build
or
waf configure && waf
Install the library (optional)
(sudo) waf install
If you want to make a clean installation
(sudo) waf distclean configure build install
In order to set the desired compiler define the environment variable CXX=<g++,clang++,icpc> (gnu, clang and intel compiler respectively).
AVX support with optimization flags is active by default. If you want disable this run the configure with debug
flag:
waf configure --debug
Compile static library (default option)
waf configure --static
Compile shared library
waf configure --shared
Define a specific installation path
waf configure --prefix=/path/to/install/folder
Once the library is compiled all the examples can be run with
./build/src/examples/<name_example>