Skip to content

Commit 8d912dd

Browse files
committed
[test][advalue] Add rudimentary test of ADValue
The test is still missing checks for many features.
1 parent 611dc1f commit 8d912dd

File tree

2 files changed

+387
-0
lines changed

2 files changed

+387
-0
lines changed

ADOL-C/boost-test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ set(SOURCE_FILES
5858
adouble.cpp
5959
main.cpp
6060
traceCompositeTests.cpp
61+
tracelessADValue.cpp
6162
tracelessCompositeTests.cpp
6263
tracelessOperatorScalar.cpp
6364
tracelessOperatorVector.cpp
Lines changed: 386 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,386 @@
1+
#define BOOST_TEST_DYN_LINK
2+
3+
#include <limits>
4+
#include <type_traits>
5+
6+
#include <boost/test/unit_test.hpp>
7+
8+
//**************************************************
9+
//* Test for the traceless forward mode
10+
//* based on adolc::ADValue
11+
//*
12+
//* Author: Carsten Graeser
13+
//**************************************************
14+
15+
//**************************************************
16+
//* Using ADValue requires C++20 or later
17+
//**************************************************
18+
#if __cplusplus >= 202002L
19+
20+
#include <adolc/advalue.h>
21+
22+
//**************************************************
23+
//* Some utilities for testing
24+
//**************************************************
25+
26+
/**
27+
* \brief Helper function for checking an ADValue
28+
*
29+
* \param checkDim Correct dimension of argument space
30+
* \param value Correct value
31+
*/
32+
template <class T, std::size_t order, std::size_t dim>
33+
void check(const adolc::ADValue<T, order, dim> &adValue, std::size_t checkDim,
34+
T value) {
35+
BOOST_TEST(adValue.dimension() == checkDim);
36+
// Check value
37+
BOOST_TEST(adValue.partial() == value);
38+
}
39+
40+
/**
41+
* \brief Helper function for checking an ADValue
42+
*
43+
* \param checkDim Correct dimension of argument space
44+
* \param value Correct value
45+
* \param d Unary callback computing correct first order partial derivatives
46+
*/
47+
template <class T, std::size_t order, std::size_t dim, class D_Callback>
48+
void check(const adolc::ADValue<T, order, dim> &adValue, std::size_t checkDim,
49+
T value, D_Callback &&d) {
50+
check(adValue, checkDim, value);
51+
// Check 1st order derivatives
52+
if constexpr (order >= 1)
53+
for (std::size_t i = 0; i < adValue.dimension(); ++i)
54+
BOOST_TEST(adValue.partial(i) == d(i));
55+
}
56+
57+
/**
58+
* \brief Helper function for checking an ADValue
59+
*
60+
* \param checkDim Correct dimension of argument space
61+
* \param value Correct value
62+
* \param d Unary callback computing correct first order partial derivatives
63+
* \param dd Binary callback computing correct second order partial derivatives
64+
*/
65+
template <class T, std::size_t order, std::size_t dim, class D_Callback,
66+
class DD_Callback>
67+
void check(const adolc::ADValue<T, order, dim> &adValue, std::size_t checkDim,
68+
T value, D_Callback &&d, DD_Callback &&dd) {
69+
check(adValue, checkDim, value, d);
70+
// Check 2nd order derivatives
71+
if constexpr (order >= 2)
72+
for (std::size_t i = 0; i < adValue.dimension(); ++i)
73+
for (std::size_t j = 0; j < adValue.dimension(); ++j)
74+
BOOST_TEST(adValue.partial(i, j) == dd(i, j));
75+
}
76+
77+
/**
78+
* \brief Helper function object returning zero for any input arguments
79+
*/
80+
constexpr auto zero = [](auto... i) { return 0; };
81+
82+
/**
83+
* \brief Create example value of static size
84+
*
85+
* The resulting ADValue's value is set to seed,
86+
* while the (i0,...in)-th partial derivative
87+
* is seed*i0*...*in.
88+
*/
89+
template <class T, std::size_t order, std::size_t dim>
90+
auto exampleValue(T seed) {
91+
auto x = adolc::ADValue<T, order, dim>();
92+
x.partial() = seed;
93+
if constexpr (order >= 1) {
94+
for (std::size_t i = 0; i < dim; ++i)
95+
x.partial(i) = seed * i;
96+
}
97+
if constexpr (order >= 2) {
98+
for (std::size_t i = 0; i < dim; ++i)
99+
for (std::size_t j = 0; j < dim; ++j)
100+
x.partial(i, j) = seed * i * j;
101+
}
102+
return x;
103+
}
104+
105+
/**
106+
* \brief Create example value of dynamic size
107+
*
108+
* The resulting ADValue's value is set to seed,
109+
* while the (i0,...in)-th partial derivative
110+
* is seed*i0*...*in.
111+
*/
112+
template <class T, std::size_t order>
113+
auto exampleValue(std::size_t dim, T seed) {
114+
auto x = adolc::ADValue<T, order, adolc::dynamicDim>(0, 0, dim);
115+
x.partial() = seed;
116+
if constexpr (order >= 1) {
117+
for (std::size_t i = 0; i < dim; ++i)
118+
x.partial(i) = seed * i;
119+
}
120+
if constexpr (order >= 2) {
121+
for (std::size_t i = 0; i < dim; ++i)
122+
for (std::size_t j = 0; j < dim; ++j)
123+
x.partial(i, j) = seed * i * j;
124+
}
125+
return x;
126+
}
127+
128+
/**
129+
* \brief Call check with a few combinations of base type order and dimension
130+
*/
131+
template <class Check> void defaultTestSuite(Check &&checkCallBack) {
132+
checkCallBack.template operator()<double, 0, 0>();
133+
checkCallBack.template operator()<double, 0, 1>();
134+
checkCallBack.template operator()<double, 0, 2>();
135+
checkCallBack.template operator()<double, 0, 3>();
136+
checkCallBack.template operator()<double, 1, 0>();
137+
checkCallBack.template operator()<double, 1, 1>();
138+
checkCallBack.template operator()<double, 1, 2>();
139+
checkCallBack.template operator()<double, 1, 3>();
140+
checkCallBack.template operator()<double, 2, 0>();
141+
checkCallBack.template operator()<double, 2, 1>();
142+
checkCallBack.template operator()<double, 2, 2>();
143+
checkCallBack.template operator()<double, 2, 3>();
144+
145+
checkCallBack.template operator()<float, 0, 0>();
146+
checkCallBack.template operator()<float, 0, 1>();
147+
checkCallBack.template operator()<float, 0, 2>();
148+
checkCallBack.template operator()<float, 0, 3>();
149+
checkCallBack.template operator()<float, 1, 0>();
150+
checkCallBack.template operator()<float, 1, 1>();
151+
checkCallBack.template operator()<float, 1, 2>();
152+
checkCallBack.template operator()<float, 1, 3>();
153+
checkCallBack.template operator()<float, 2, 0>();
154+
checkCallBack.template operator()<float, 2, 1>();
155+
checkCallBack.template operator()<float, 2, 2>();
156+
checkCallBack.template operator()<float, 2, 3>();
157+
}
158+
159+
//**************************************************
160+
//* Test of individual feature of ADValue
161+
//**************************************************
162+
163+
BOOST_AUTO_TEST_SUITE(traceless_vector)
164+
165+
BOOST_AUTO_TEST_CASE(ADValueConstructor) {
166+
defaultTestSuite([]<class T, std::size_t order, std::size_t dim>() {
167+
// Check default dimension value
168+
using ADValue_dynamic = adolc::ADValue<T, order, adolc::dynamicDim>;
169+
using ADValue_default = adolc::ADValue<T, order>;
170+
BOOST_TEST((std::is_same_v<ADValue_dynamic, ADValue_default>));
171+
172+
// Construct as constant
173+
T x = 42;
174+
check(adolc::ADValue<T, order, dim>(x), dim, x, zero, zero);
175+
check(adolc::ADValue<T, order, adolc::dynamicDim>(x), 0, x, zero, zero);
176+
177+
if constexpr (order >= 1) {
178+
// Construct as k-th input argument
179+
for (std::size_t k = 0; k < dim; ++k) {
180+
auto D = [&](auto i) { return i == k; };
181+
check(adolc::ADValue<T, order, dim>(x, k), dim, x, D, zero);
182+
check(adolc::ADValue<T, order, adolc::dynamicDim>(x, k, dim), dim, x, D,
183+
zero);
184+
}
185+
}
186+
});
187+
}
188+
189+
BOOST_AUTO_TEST_CASE(ADValueAssign) {
190+
defaultTestSuite([]<class T, std::size_t order, std::size_t dim>() {
191+
T aValue = 42;
192+
T bValue = 23;
193+
T cValue = 237;
194+
195+
{
196+
auto a = adolc::ADValue<T, order, dim>(aValue);
197+
auto b = adolc::ADValue<T, order, dim>(bValue);
198+
check(a, dim, aValue, zero, zero);
199+
a = b;
200+
check(a, dim, bValue, zero, zero);
201+
a = cValue;
202+
check(a, dim, cValue, zero, zero);
203+
}
204+
{
205+
auto a = adolc::ADValue<T, order, adolc::dynamicDim>(aValue);
206+
auto b = adolc::ADValue<T, order, adolc::dynamicDim>(bValue);
207+
check(a, 0, aValue, zero, zero);
208+
a = b;
209+
check(a, 0, bValue, zero, zero);
210+
a = cValue;
211+
check(a, 0, cValue, zero, zero);
212+
}
213+
214+
if (dim > 0) {
215+
{
216+
auto a = adolc::ADValue<T, order, dim>(aValue, 0);
217+
auto b = adolc::ADValue<T, order, dim>(bValue, dim - 1);
218+
check(a, dim, aValue, [](auto i) { return i == 0; }, zero);
219+
a = b;
220+
check(a, dim, bValue, [](auto i) { return i == (dim - 1); }, zero);
221+
a = cValue;
222+
check(a, dim, cValue, zero, zero);
223+
}
224+
{
225+
auto a = adolc::ADValue<T, order, adolc::dynamicDim>(aValue, 0, 1);
226+
auto b =
227+
adolc::ADValue<T, order, adolc::dynamicDim>(bValue, dim - 1, dim);
228+
check(a, 1, aValue, [](auto i) { return i == 0; }, zero);
229+
a = b;
230+
check(a, dim, bValue, [](auto i) { return i == (dim - 1); }, zero);
231+
a = cValue;
232+
check(a, dim, cValue, zero, zero);
233+
}
234+
}
235+
});
236+
}
237+
238+
BOOST_AUTO_TEST_CASE(ADValueSum) {
239+
defaultTestSuite([]<class T, std::size_t order, std::size_t dim>() {
240+
T aValue = 42;
241+
T bValue = 23;
242+
243+
{
244+
auto a = exampleValue<T, order, dim>(aValue);
245+
auto b = exampleValue<T, order, dim>(bValue);
246+
247+
auto c = a + b;
248+
check(
249+
c, dim, aValue + bValue,
250+
[&](auto i) { return (aValue + bValue) * i; },
251+
[&](auto i, auto j) { return (aValue + bValue) * i * j; });
252+
253+
auto d = a;
254+
d += b;
255+
check(
256+
d, dim, aValue + bValue,
257+
[&](auto i) { return (aValue + bValue) * i; },
258+
[&](auto i, auto j) { return (aValue + bValue) * i * j; });
259+
}
260+
261+
{
262+
auto a = exampleValue<T, order>(dim, aValue);
263+
auto b = exampleValue<T, order>(dim, bValue);
264+
265+
auto c = a + b;
266+
check(
267+
c, dim, aValue + bValue,
268+
[&](auto i) { return (aValue + bValue) * i; },
269+
[&](auto i, auto j) { return (aValue + bValue) * i * j; });
270+
271+
auto d = a;
272+
d += b;
273+
check(
274+
d, dim, aValue + bValue,
275+
[&](auto i) { return (aValue + bValue) * i; },
276+
[&](auto i, auto j) { return (aValue + bValue) * i * j; });
277+
}
278+
});
279+
}
280+
281+
BOOST_AUTO_TEST_CASE(ADValueDiff) {
282+
defaultTestSuite([]<class T, std::size_t order, std::size_t dim>() {
283+
T aValue = 42;
284+
T bValue = 23;
285+
286+
{
287+
auto a = exampleValue<T, order, dim>(aValue);
288+
auto b = exampleValue<T, order, dim>(bValue);
289+
290+
auto c = a - b;
291+
check(
292+
c, dim, aValue - bValue,
293+
[&](auto i) { return (aValue - bValue) * i; },
294+
[&](auto i, auto j) { return (aValue - bValue) * i * j; });
295+
296+
auto d = a;
297+
d -= b;
298+
check(
299+
d, dim, aValue - bValue,
300+
[&](auto i) { return (aValue - bValue) * i; },
301+
[&](auto i, auto j) { return (aValue - bValue) * i * j; });
302+
}
303+
304+
{
305+
auto a = exampleValue<T, order>(dim, aValue);
306+
auto b = exampleValue<T, order>(dim, bValue);
307+
308+
auto c = a - b;
309+
check(
310+
c, dim, aValue - bValue,
311+
[&](auto i) { return (aValue - bValue) * i; },
312+
[&](auto i, auto j) { return (aValue - bValue) * i * j; });
313+
314+
auto d = a;
315+
d -= b;
316+
check(
317+
d, dim, aValue - bValue,
318+
[&](auto i) { return (aValue - bValue) * i; },
319+
[&](auto i, auto j) { return (aValue - bValue) * i * j; });
320+
}
321+
});
322+
}
323+
324+
BOOST_AUTO_TEST_CASE(ADValueMult) {
325+
defaultTestSuite([]<class T, std::size_t order, std::size_t dim>() {
326+
T aValue = 42;
327+
T bValue = 23;
328+
329+
{
330+
auto a = exampleValue<T, order, dim>(aValue);
331+
auto b = exampleValue<T, order, dim>(bValue);
332+
333+
auto c = a * b;
334+
check(
335+
c, dim, aValue * bValue,
336+
[&](auto i) { return 2 * aValue * bValue * i; },
337+
[&](auto i, auto j) { return 4 * aValue * bValue * i * j; });
338+
339+
auto d = a;
340+
d *= b;
341+
check(
342+
d, dim, aValue * bValue,
343+
[&](auto i) { return 2 * aValue * bValue * i; },
344+
[&](auto i, auto j) { return 4 * aValue * bValue * i * j; });
345+
}
346+
347+
{
348+
auto a = exampleValue<T, order>(dim, aValue);
349+
auto b = exampleValue<T, order>(dim, bValue);
350+
351+
auto c = a * b;
352+
check(
353+
c, dim, aValue * bValue,
354+
[&](auto i) { return 2 * aValue * bValue * i; },
355+
[&](auto i, auto j) { return 4 * aValue * bValue * i * j; });
356+
357+
auto d = a;
358+
d *= b;
359+
check(
360+
d, dim, aValue * bValue,
361+
[&](auto i) { return 2 * aValue * bValue * i; },
362+
[&](auto i, auto j) { return 4 * aValue * bValue * i * j; });
363+
}
364+
});
365+
}
366+
367+
//**************************************************
368+
//* ToDo: Add checks for the following features
369+
//* - Division of ADValue and ADValue
370+
//* - Arithmetic operations of ADValue and raw value
371+
//* - Nonlinear functions
372+
//**************************************************
373+
374+
BOOST_AUTO_TEST_SUITE_END()
375+
376+
#else //__cplusplus >= 202002L
377+
378+
BOOST_AUTO_TEST_SUITE(traceless_vector)
379+
BOOST_AUTO_TEST_CASE(ADValueNotTested) {
380+
std::cout << "ADOL-C Warning: ADValue is not tested since test is not "
381+
"compiled with C++20 support."
382+
<< std::endl;
383+
}
384+
BOOST_AUTO_TEST_SUITE_END()
385+
386+
#endif //__cplusplus >= 202002L

0 commit comments

Comments
 (0)