File: random_walk.cpp

package info (click to toggle)
boost1.83 1.83.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 545,632 kB
  • sloc: cpp: 3,857,086; xml: 125,552; ansic: 34,414; python: 25,887; asm: 5,276; sh: 4,799; ada: 1,681; makefile: 1,629; perl: 1,212; pascal: 1,139; sql: 810; yacc: 478; ruby: 102; lisp: 24; csh: 6
file content (153 lines) | stat: -rw-r--r-- 5,089 bytes parent folder | download | duplicates (14)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//---------------------------------------------------------------------------//
// Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com>
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
// See http://boostorg.github.com/compute for more information.
//---------------------------------------------------------------------------//

#include <iostream>

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <boost/compute/system.hpp>
#include <boost/compute/algorithm/inclusive_scan.hpp>
#include <boost/compute/algorithm/inclusive_scan.hpp>
#include <boost/compute/interop/opencv/core.hpp>
#include <boost/compute/interop/opencv/highgui.hpp>
#include <boost/compute/random/default_random_engine.hpp>
#include <boost/compute/random/uniform_real_distribution.hpp>
#include <boost/compute/utility/source.hpp>

namespace compute = boost::compute;

// this example uses the random-number generation functions in Boost.Compute
// to calculate a large number of random "steps" and then plots the final
// random "walk" in a 2D image on the GPU and displays it with OpenCV
int main()
{
    // number of random steps to take
    size_t steps = 250000;

    // height and width of image
    size_t height = 800;
    size_t width = 800;

    // get default device and setup context
    compute::device gpu = compute::system::default_device();
    compute::context context(gpu);
    compute::command_queue queue(context, gpu);

    using compute::int2_;

    // calaculate random values for each step
    compute::vector<float> random_values(steps, context);
    compute::default_random_engine random_engine(queue);
    compute::uniform_real_distribution<float> random_distribution(0.f, 4.f);

    random_distribution.generate(
        random_values.begin(), random_values.end(), random_engine, queue
    );

    // calaculate coordinates for each step
    compute::vector<int2_> coordinates(steps, context);

    // function to convert random values to random directions (in 2D)
    BOOST_COMPUTE_FUNCTION(int2_, take_step, (const float x),
    {
        if(x < 1.f){
            // move right
            return (int2)(1, 0);
        }
        if(x < 2.f){
            // move up
            return (int2)(0, 1);
        }
        if(x < 3.f){
            // move left
            return (int2)(-1, 0);
        }
        else {
            // move down
            return (int2)(0, -1);
        }
    });

    // transform the random values into random steps
    compute::transform(
        random_values.begin(), random_values.end(), coordinates.begin(), take_step, queue
    );

    // set staring position
    int2_ starting_position(width / 2, height / 2);
    compute::copy_n(&starting_position, 1, coordinates.begin(), queue);

    // scan steps to calculate position after each step
    compute::inclusive_scan(
        coordinates.begin(), coordinates.end(), coordinates.begin(), queue
    );

    // create output image
    compute::image2d image(
        context, width, height, compute::image_format(CL_RGBA, CL_UNSIGNED_INT8)
    );

    // program with two kernels, one to fill the image with white, and then
    // one the draw to points calculated in coordinates on the image
    const char draw_walk_source[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
        __kernel void draw_walk(__global const int2 *coordinates,
                                __write_only image2d_t image)
        {
            const uint i = get_global_id(0);
            const int2 coord = coordinates[i];

            if(coord.x > 0 && coord.x < get_image_width(image) &&
               coord.y > 0 && coord.y < get_image_height(image)){
                uint4 black = { 0, 0, 0, 0 };
                write_imageui(image, coord, black);
            }
        }

        __kernel void fill_white(__write_only image2d_t image)
        {
            const int2 coord = { get_global_id(0), get_global_id(1) };

            if(coord.x < get_image_width(image) &&
               coord.y < get_image_height(image)){
                uint4 white = { 255, 255, 255, 255 };
                write_imageui(image, coord, white);
            }
        }
    );

    // build the program
    compute::program draw_program =
        compute::program::build_with_source(draw_walk_source, context);

    // fill image with white
    compute::kernel fill_kernel(draw_program, "fill_white");
    fill_kernel.set_arg(0, image);

    const size_t offset[] = { 0, 0 };
    const size_t bounds[] = { width, height };

    queue.enqueue_nd_range_kernel(fill_kernel, 2, offset, bounds, 0);

    // draw random walk
    compute::kernel draw_kernel(draw_program, "draw_walk");
    draw_kernel.set_arg(0, coordinates);
    draw_kernel.set_arg(1, image);
    queue.enqueue_1d_range_kernel(draw_kernel, 0, coordinates.size(), 0);

    // show image
    compute::opencv_imshow("random walk", image, queue);

    // wait and return
    cv::waitKey(0);

    return 0;
}