File: side_effects.cpp

package info (click to toggle)
halide 14.0.0-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 49,124 kB
  • sloc: cpp: 238,722; makefile: 4,303; python: 4,047; java: 1,575; sh: 1,384; pascal: 211; xml: 165; javascript: 43; ansic: 34
file content (130 lines) | stat: -rw-r--r-- 3,245 bytes parent folder | download
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
#include "Halide.h"
#include <math.h>
#include <stdio.h>

using namespace Halide;

// NB: You must compile with -rdynamic for llvm to be able to find the
// appropriate symbols

// Many things that are difficult to do with Halide can be hacked in
// using reductions that call extern C functions. In general this is a
// bad way to do things, because you've tied yourself to C, which
// means no GPU.  Additionally, if your reduction has pure dimensions,
// you need to take care to make your extern functions
// thread-safe.

// Here we use an extern call to print an ascii-art Mandelbrot set.
#ifdef _WIN32
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT
#endif

int call_count = 0;
extern "C" DLLEXPORT int draw_pixel(int x, int y, int val) {
    call_count++;
    static int last_y = 0;
    if (y != last_y) {
        printf("\n");
        last_y = y;
    }

    const char *code = " .:-~*={}&%#@";

    if (val >= static_cast<int>(strlen(code))) {
        val = static_cast<int>(strlen(code)) - 1;
    }
    printf("%c", code[val]);
    return 0;
}
HalideExtern_3(int, draw_pixel, int, int, int);

// Make a complex number type using Tuples
class Complex {
    Tuple t;

public:
    Complex(Expr real, Expr imag)
        : t(real, imag) {
    }
    Complex(Tuple tup)
        : t(tup) {
    }
    Complex(FuncRef f)
        : t(Tuple(f)) {
    }
    Expr real() const {
        return t[0];
    }
    Expr imag() const {
        return t[1];
    }

    operator Tuple() const {
        return t;
    }
};

// Define the usual complex arithmetic
Complex operator+(const Complex &a, const Complex &b) {
    return Complex(a.real() + b.real(),
                   a.imag() + b.imag());
}

Complex operator-(const Complex &a, const Complex &b) {
    return Complex(a.real() - b.real(),
                   a.imag() - b.imag());
}

Complex operator*(const Complex &a, const Complex &b) {
    return Complex(a.real() * b.real() - a.imag() * b.imag(),
                   a.real() * b.imag() + a.imag() * b.real());
}

Complex conjugate(const Complex &a) {
    return Complex(a.real(), -a.imag());
}

Expr magnitude(Complex a) {
    return (a * conjugate(a)).real();
}

int main(int argc, char **argv) {
    Var x, y;

    Func mandelbrot;
    // Use a different scale on x and y because terminal characters
    // are not square. Arbitrarily chosen to fit the set nicely.
    Complex initial(x / 20.0f, y / 8.0f);
    Var z;
    mandelbrot(x, y, z) = Complex(0.0f, 0.0f);
    RDom t(1, 40);
    Complex current = mandelbrot(x, y, t - 1);
    mandelbrot(x, y, t) = current * current + initial;

    // How many iterations until something escapes a circle of radius 2?
    Func count;
    Tuple escape = argmin(magnitude(mandelbrot(x, y, t)) < 4);
    // If it never escapes, use the value 0
    count(x, y) = select(escape[1], 0, escape[0]);

    RDom r(-45, 71, -10, 21);
    Func render;
    render() += draw_pixel(r.x, r.y, count(r.x, r.y));

    mandelbrot.compute_at(render, r.x);

    render.realize();

    printf("\n");

    // Check draw_pixel was called the right number of times.
    if (call_count != 71 * 21) {
        printf("Something went wrong\n");
        return -1;
    }

    printf("Success!\n");
    return 0;
}