Skip to content

Commit

Permalink
Expanded documentation by describing ways of defining integrands.
Browse files Browse the repository at this point in the history
  • Loading branch information
adolfomunoz committed May 28, 2021
1 parent 8e18c66 commit 612d343
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 2 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ That would be enough to use all the features of the library. There are other alt

Integrating a function in a specific n-dimensional range is rather simple. You need the following information:
- An *integrator*, a numerical integration method.
- An *integrand*, a function to be integrated. It's only parameter has to be a `std::array<F,N>`, where `F` is a floating point number and `N` is the number of dimensions.
- An *integrand*, a function to be integrated. It's only parameter has to be a `std::array<F,N>`, 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)
- A *range*, the integration domain, that is composed on two `std::array<F,N>` marking the limits of the integration domain.

Example:
Expand Down
2 changes: 1 addition & 1 deletion doc/installation.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Installation
# `viltrum` - Installation

`viltrum` is a header-only library, so installation is rather simple (it does not require any compilation process). You just need to download the library in a specific folder:

Expand Down
112 changes: 112 additions & 0 deletions doc/integrands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# `viltrum` - Integrand definition

Defining integrands in `viltrum` for their integration with any numerical method is simple. You need to define a function that has the form:

```cpp
V f(const std::array<F,N>& x)
```
where:
- `N` is the number of dimensions explored by the function. It should be the same number than the dimensions of the integration range that is defined when integrating.
- `F` is a floating point value that explores the function.
- `V` is the resulting value of the function. `V` needs to have some numeric operations: addition `+`, multiplication by a scalar `*`, division by a scalar `/`... In general, floating point numbers and standard numerical algebra arrays (Eigen::Array) comply with this requirements.
There are several ways in which such an integrand can be defined in C++, and each of them will be illustrated with an working example. All of the examples below approximate the volume of a sphere using Monte Carlo integration.
Integrands can be defined:
- Through a standard C++ function:
```cpp
#include <viltrum/viltrum.h>
float sphere(const std::array<float,3>& 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<float,3>{-1.0f,-1.0f,-1.0f},std::array<float,3>{1.0f,1.0f,1.0f});
std::cout<<"Sphere volume = "<<method.integrate(sphere,range)<<std::endl;
}
```

- Through a class that represents a function (defining its `operator()`):

```cpp
#include <viltrum/viltrum.h>
class Sphere {
public:
float operator()(const std::array<float,3>& x) const {
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<float,3>{-1.0f,-1.0f,-1.0f},std::array<float,3>{1.0f,1.0f,1.0f});
std::cout<<"Sphere volume = "<<method.integrate(Sphere(),range)<<std::endl;
}
```
- Through a lambda expression:
```cpp
#include <viltrum/viltrum.h>
int main() {
unsigned long samples = 1024;
auto method = viltrum::integrator_monte_carlo_uniform(samples);
auto range = viltrum::range(std::array<float,3>{-1.0f,-1.0f,-1.0f},std::array<float,3>{1.0f,1.0f,1.0f});
std::cout<<"Sphere volume = "<<method.integrate([] (const std::array<float,3>& x) { return (x[0]*x[0]+x[1]*x[1]+x[2]*x[2])<1.0f?1.0f:0.0f; },range)<<std::endl;
}
```

## Wrapping normal functions

It is true that defining functions having `std::array`s as parameters is rather unusual and unintuitive. More often you will define a function as having multiple independent parameters. In order to fit those as `viltrum` integrands, the library provides a wrapper that automatically does that, which is unsurprisingly named `viltrum::function_wrapper(...)`. You can wrap any function in the invocation of the integration method.

Lets see how to apply the wrapper with similar examples than above:

- With a C++ function:
```cpp
#include <viltrum/viltrum.h>
float sphere_parameters(float x, float y, float z) {
return (x*x + y*y + z*z)<=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<float,3>{-1.0f,-1.0f,-1.0f},std::array<float,3>{1.0f,1.0f,1.0f});
std::cout<<"Sphere volume = "<<method.integrate(viltrum::function_wrapper(sphere_parameters),range)<<std::endl;
}
```
- With a C++ class representing a function with an `operator()`:
```cpp
#include <viltrum/viltrum.h>
class SphereParameters {
public:
float operator()(float x, float y, float z) const {
return (x*x + y*y + z*z)<=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<float,3>{-1.0f,-1.0f,-1.0f},std::array<float,3>{1.0f,1.0f,1.0f});
std::cout<<"Sphere volume = "<<method.integrate(viltrum::function_wrapper(SphereParameters()),range)<<std::endl;
}
```

- With a lambda expression:
```cpp
#include <viltrum/viltrum.h>
int main() {
unsigned long samples = 1024;
auto method = viltrum::integrator_monte_carlo_uniform(samples);
auto range = viltrum::range(std::array<float,3>{-1.0f,-1.0f,-1.0f},std::array<float,3>{1.0f,1.0f,1.0f});
std::cout<<"Sphere volume = "<<method.integrate(viltrum::function_wrapper([] (float x, float y, float z) { return (x*x + y*y + z*z)<=1.0f?1.0f:0.0f; }),
range)<<std::endl;
}
```




0 comments on commit 612d343

Please sign in to comment.