# viltrum
VILTRUM: Varied Integration Layouts for arbiTRary integrals in a Unified Manner - A C++17 header-only library that provides a set of numerical integration routines. This library was generated during research for our paper:
ACM Transactions on Graphics - 2021
Miguel Crespo
·
Adrian Jarabo
·
Adolfo Muñoz
## Installation
`viltrum` is a header-only library and has no external dependencies, so installation is rather simple (it does not require any compilation process). You just need to download the library in a specific folder:
```
folder> git clone https://github.com/adolfomunoz/viltrum.git
```
Then make sure `folder` is within the included directories (`-Ifolder` parameter in g++, `include_directories("folder")` in CMake) and
include it from C++.
```cpp
#include
```
That would be enough to use all the features of the library. There are other alternatives that might be more comfortable for you, see them [here](doc/installation.md). There is a CMake-based building system for several example and test executable files that automatically downloads external dependencies and compiles all executables but it is not needed for the libray's usage.
## Usage
Integrating a function in a specific n-dimensional range is rather simple. You need the following information:
- An *integrator*, a numerical integration method, for which there are [several to choose from](doc/integrators.md).
- An *integrand*, a function to be integrated. It's only parameter has to be a `std::array`, where `F` is a floating point number and `N` is the number of dimensions. There are [several ways in which such integrand can be defined](doc/integrands.md). The integrand can return any numeric value, or, in general, any data type that supports addition and multiplication by a scalar (tested with [Eigen arrays](https://eigen.tuxfamily.org/dox/group__TutorialArrayClass.html) ).
- A *range*, the integration domain, that is composed on two `std::array` marking the limits of the potentially multidimensional integration domain, which [can be defined in different ways](doc/ranges.md).
Example:
```cpp
float sphere(const std::array& x) {
return (x[0]*x[0]+x[1]*x[1]+x[2]*x[2])<=1.0f?1.0f:0.0f;
}
int main() {
unsigned long samples = 1024;
auto method = viltrum::integrator_monte_carlo_uniform(samples);
auto range = viltrum::range(std::array{-1.0f,-1.0f,-1.0f},std::array{1.0f,1.0f,1.0f});
std::cout<<"Sphere volume = "<& x) { return (x[1]{0,0},std::array{1,1});
float output_array[16];
//...
}
```
bin integrators can be used as follows (1D example):
```cpp
auto output_array_access = [&output_array] (const std::array& i) -> float& { return output_array[i[0]]; };
integrator_bins.integrate(output_array_access,std::array{16},slope,range);
for (float f : output_array) std::cout<& i) -> float& { return output_array[4*i[0]+i[1]]; };
integrator_bins.integrate(output_array_access_2d,std::array{4,4},slope,range);
```
Additionally, the `viltrum` library offers a functional version of the same method:
```cpp
integrate_bins(integrator_bins,output_array_access,std::array{16},slope,range);
integrate_bins(integrator_bins,output_array_access_2d,std::array{4,4},slope,range);
```
This functional version is able to deduce the bin accesor as well as the resolution for `std::vector` data types, in which there is only one parameter defining the binning structure:
```cpp
std::vector output_vector(16);
integrate_bins(integrator_bins, output_vector, slope, range);
for (float f : output_vector) std::cout<> output_matrix(4,std::vector(4));
integrate_bins(integrator_bins, output_matrix, slope, range);
std::cout<& row : output_matrix) {
for (float f : row) std::cout<