Skip to content

Commit

Permalink
Add tutorial on testing
Browse files Browse the repository at this point in the history
  • Loading branch information
mattiaisgro committed Dec 19, 2024
1 parent a8cfead commit 17edd6c
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 1 deletion.
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,36 @@
Theoretica provides methods for **scientific computing**, statistical analysis of experimental data and numerical approximation. The aim of the project is to give simple and immediate access to powerful algorithms for scientific and engineering software. The library is tested using [Chebyshev](https://github.com/chaotic-society/chebyshev), a unit testing framework specifically developed for scientific and numerical software.

## A short example

The following code solves the Lorenz attractor and writes the solution to a file:

```cpp
vec3 f(real t, vec3 v) {

const real a = 13, b = 20, c = 8./3.;
const real x = v[0], y = v[1], z = v[2];

return {
y * a - x * a,
x * b - x * z,
x * y - c * z
};
}

int main() {

// Initial conditions
vec3 x0 = {0.0, 0.1, 0.0};

// Use Runge-Kutta between t=0 and 50
auto sol = ode::solve_rk4(f, x0, 0.0, 50.0);

std::ofstream file ("lorenz.dat");
file << sol;
}

```
## Features
Expand Down
53 changes: 53 additions & 0 deletions TESTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Testing

The [Chebyshev](https://github.com/chaotic-society/chebyshev) testing framework is used to validate Theoretica's numerical methods. In particular, the `prec` module is used to estimate the precision of the methods, while the `benchmark` module is used to benchmark performance-critical code.

## Directory Structure
All test programs are stored inside the `test` directory and Make may be used to execute them, using `make test` for precision testing and `make benchmark` for benchmarking. Precision testing programs are stored in `test/prec`, with implementation files organized by module and called `test_modulename.cpp`, while benchmarks are inside the `test/benchmark` folder and are called `benchmark_modulename.cpp`.

### Precision Testing
The `prec` module provides two main functions, `prec::estimate` and `prec::equals`. The `prec::estimate` function uses an estimator function to estimate error integrals (or sums) over a domain of a certain function with respect to an exact or better implementation. Chebyshev provides some built-in estimators for common applications, such as real functions using quadrature of integrals or Monte Carlo methods. On the other hand, `prec::equals` compares two values, checking that their distance is smaller than the tolerance (with respect to an arbitrary distance function). The module is initialized using `prec::setup("module name")` and terminated using `prec::terminate()`:

```cpp
prec::setup("module name");

//...

prec::terminate();
```
The test cases are written between the two directives. The settings for the module are available by modifying the `prec::settings` structure directly. For example, the following code sets an output file:
```cpp
prec::settings.outputFiles = { "output.csv" };
```

By default, the output format is CSV, as is generally used for Theoretica's test output. The `estimate_options` and `equation_options` structures are used to store additional options which may be used between many different test cases. This code shows how to use `prec::estimate` with a custom estimator:

```cpp
auto options = prec::estimate_options<real, real>(
prec::interval(0.0, 1.0),
prec::estimator::quadrature1D(),
1E-04
);

prec::estimate(
"derivative",
approxFunction, exactFunction, options
);
```

The template parameters to `estimate_options` are the return and argument types of the function under test, while the constructor arguments are the name of the test case (usually the function name), the function under test and a reference function, either exact or more accurate (sometimes it's easier to test over known equations with expected function equal to zero or a constant). The last argument provides the options for the test case, with the first argument being an interval or list of intervals which determine the domain, the second being the estimator to use and the last the tolerance value for the tests. The following code uses the `prec::equals` function to compute the distance between two values, in this case two polynomials, using a custom provided distance function:

```cpp
auto options = prec::equation_options<polynomial<real>>(
1E-08, distance_polyn
);

prec::equals(
"polynomial",
P1, P2, options
);
```

The template parameter for `equation_options` is the type of variable which will be compared, while `distance_polyn` is a custom distance function taking in two polynomials and computing their distance over the coefficients (the first argument to the constructor is the tolerance value). If a distance function is not provided, the ordering `operator<` is used to compute the absolute value of any ordered type.
1 change: 0 additions & 1 deletion test/prec/test_optimization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ int main(int argc, char const *argv[]) {
prec::setup("optimization");

prec::settings.outputFiles = { "test/prec/prec_optimization.csv" };
prec::settings.verboseOutput = true;

{
// root = 0.690389757422;
Expand Down

0 comments on commit 17edd6c

Please sign in to comment.