ddemidov / vexcl
1
#define BOOST_TEST_MODULE KernelGenerator
2
#include <boost/test/unit_test.hpp>
3
#include <boost/phoenix/phoenix.hpp>
4
#include <vexcl/vector.hpp>
5
#include <vexcl/generator.hpp>
6
#include <vexcl/tagged_terminal.hpp>
7
#include "context_setup.hpp"
8

9
template <class state_type>
10
state_type sys_func(const state_type &x) {
11 6
    return sin(x);
12
}
13

14
template <class state_type, class SysFunction>
15
void runge_kutta_2(SysFunction sys, state_type &x, double dt) {
16 6
    state_type k1 = dt * sys(x);
17 6
    state_type k2 = dt * sys(x + 0.5 * k1);
18

19 6
    x += k2;
20
}
21

22 6
BOOST_AUTO_TEST_CASE(kernel_generator)
23
{
24
    typedef vex::symbolic<double> sym_state;
25

26
    const size_t n  = 1024;
27 6
    const double dt = 0.01;
28

29 6
    std::ostringstream body;
30 6
    vex::generator::set_recorder(body);
31

32 6
    sym_state sym_x(sym_state::VectorParameter);
33

34
    // Record expression sequence.
35 6
    runge_kutta_2(sys_func<sym_state>, sym_x, dt);
36

37
    // Build kernel.
38 6
    auto kernel = vex::generator::build_kernel(
39 6
            ctx, "rk2_stepper", body.str(), sym_x);
40

41 6
    std::vector<double> x = random_vector<double>(n);
42 6
    vex::vector<double> X(ctx, x);
43

44 6
    for(int i = 0; i < 100; i++) kernel(X);
45

46 6
    check_sample(X, [&](size_t idx, double a) {
47 6
            double s = x[idx];
48 6
            for(int i = 0; i < 100; i++)
49 6
                runge_kutta_2(sys_func<double>, s, dt);
50

51 6
            BOOST_CHECK_CLOSE(a, s, 1e-8);
52 6
            });
53
}
54

55 6
BOOST_AUTO_TEST_CASE(kernel_generator_with_user_function)
56
{
57
    typedef vex::symbolic<double> sym_state;
58

59
    const size_t n  = 1024;
60

61 6
    std::ostringstream body;
62 6
    vex::generator::set_recorder(body);
63

64 6
    sym_state sym_x(sym_state::VectorParameter, sym_state::Const);
65 6
    sym_state sym_y(sym_state::VectorParameter);
66

67 6
    VEX_FUNCTION(double, sin2, (double, x),
68
            double s = sin(x);
69
            return s * s;
70
            );
71

72 6
    sym_y = sin2(sym_x);
73

74 6
    auto kernel = vex::generator::build_kernel(
75 6
            ctx, "test_sin2", body.str(), sym_x, sym_y);
76

77 6
    vex::vector<double> X(ctx, random_vector<double>(n));
78 6
    vex::vector<double> Y(ctx, n);
79

80 6
    for(int i = 0; i < 100; i++) kernel(X, Y);
81

82 6
    check_sample(X, Y, [&](size_t, double x, double y) {
83 6
            BOOST_CHECK_CLOSE(y, sin(x) * sin(x), 1e-8);
84 6
            });
85
}
86 6
BOOST_AUTO_TEST_CASE(function_generator)
87
{
88
    typedef vex::symbolic<double> sym_state;
89

90
    const size_t n  = 1024;
91 6
    const double dt = 0.01;
92

93 6
    std::ostringstream body;
94 6
    vex::generator::set_recorder(body);
95

96 6
    sym_state sym_x(sym_state::VectorParameter);
97

98
    // Record expression sequence.
99 6
    runge_kutta_2(sys_func<sym_state>, sym_x, dt);
100

101
    // Build function.
102
    // Body string has to be static:
103 6
    static std::string function_body = vex::generator::make_function(
104 6
            body.str(), sym_x, sym_x);
105

106 6
    VEX_FUNCTION_S(double, rk2, (double, prm1), function_body);
107

108 6
    std::vector<double> x = random_vector<double>(n);
109 6
    vex::vector<double> X(ctx, x);
110

111 6
    for(int i = 0; i < 100; i++) {
112 6
        X = rk2(X);
113
    }
114

115 6
    check_sample(X, [&](size_t idx, double a) {
116 6
            double s = x[idx];
117 6
            for(int i = 0; i < 100; i++)
118 6
                runge_kutta_2(sys_func<double>, s, dt);
119

120 6
            BOOST_CHECK_CLOSE(a, s, 1e-8);
121 6
            });
122
}
123

124
struct rk2_stepper {
125
    double dt;
126

127 6
    rk2_stepper(double dt) : dt(dt) {}
128

129
    template <class State>
130
    State operator()(const State &x) const {
131 6
        State new_x = x;
132 6
        runge_kutta_2(sys_func<State>, new_x, dt);
133 6
        return new_x;
134
    }
135
};
136

137 6
BOOST_AUTO_TEST_CASE(function_adapter)
138
{
139
    const size_t n  = 1024;
140
    const double dt = 0.01;
141

142 6
    rk2_stepper step(dt);
143

144 6
    auto rk2 = vex::generator::make_function<double(double)>(step);
145

146 6
    std::vector<double> x = random_vector<double>(n);
147 6
    vex::vector<double> X(ctx, x);
148

149 6
    for(int i = 0; i < 100; i++) {
150 6
        X = rk2(X);
151
    }
152

153 6
    check_sample(X, [&](size_t idx, double a) {
154 6
            double s = x[idx];
155 6
            for(int i = 0; i < 100; i++) s = step(s);
156

157 6
            BOOST_CHECK_CLOSE(a, s, 1e-8);
158 6
            });
159
}
160

161 6
BOOST_AUTO_TEST_CASE(function_adapter_and_phoenix_lambda)
162
{
163
    using namespace boost::phoenix::arg_names;
164

165
    const size_t n  = 1024;
166

167 6
    auto squared_radius = vex::generator::make_function<double(double, double)>(
168 6
            arg1 * arg1 + arg2 * arg2);
169

170 6
    vex::vector<double> X(ctx, random_vector<double>(n));
171 6
    vex::vector<double> Y(ctx, random_vector<double>(n));
172

173 6
    vex::vector<double> Z = squared_radius(X, Y);
174

175 6
    check_sample(X, Y, Z, [&](size_t, double x, double y, double z) {
176 6
            BOOST_CHECK_CLOSE(z, x * x + y * y, 1e-8);
177 6
            });
178
}
179

180
/*
181
An alternative variant, which does not use the generator facility.
182
Intermediate subexpression are captured with help of 'auto' keyword, and
183
are combined into larger expression.
184

185
Note how vex::tag<>() facilitates reuse of kernel parameters.
186
*/
187 6
BOOST_AUTO_TEST_CASE(lazy_evaluation)
188
{
189
    const size_t n  = 1024;
190 6
    const double dt = 0.01;
191

192 6
    auto rk2 = [](vex::vector<double> &x, double dt) {
193 6
        auto X  = vex::tag<1>(x);
194 6
        auto DT = vex::tag<2>(dt);
195

196 6
        auto k1 = DT * sin(X);
197 6
        auto x1 = X + 0.5 * k1;
198

199 6
        auto k2 = DT * sin(x1);
200

201 6
        x = X + k2;
202 6
    };
203

204 6
    std::vector<double> x = random_vector<double>(n);
205 6
    vex::vector<double> X(ctx, x);
206

207 6
    for(int i = 0; i < 100; i++) {
208 6
        rk2(X, dt);
209
    }
210

211 6
    check_sample(X, [&](size_t idx, double a) {
212 6
            double s = x[idx];
213 6
            for(int i = 0; i < 100; i++)
214 6
                runge_kutta_2(sys_func<double>, s, dt);
215

216 6
            BOOST_CHECK_CLOSE(a, s, 1e-8);
217 6
            });
218
}
219

220 6
BOOST_AUTO_TEST_CASE(element_index)
221
{
222
    const size_t n  = 1024;
223 6
    std::vector<vex::command_queue> queue(1, ctx.queue(0));
224

225
    typedef vex::symbolic<int> sym_vector;
226

227 6
    std::ostringstream body;
228 6
    vex::generator::set_recorder(body);
229

230 6
    sym_vector sym_x(sym_vector::VectorParameter);
231

232 6
    sym_x = vex::generator::index();
233 6
    auto kernel = vex::generator::build_kernel(queue, "element_index", body.str(), sym_x);
234

235 6
    vex::vector<int> x(queue, n);
236

237 6
    kernel(x);
238

239 6
    check_sample(x, [&](size_t idx, int i) { BOOST_CHECK_EQUAL(i, idx); });
240
}
241

242 6
BOOST_AUTO_TEST_SUITE_END()

Read our documentation on viewing source code .

Loading