float CT stringification

bearophile bearophileHUGS at lycos.com
Thu Jun 5 03:31:45 PDT 2008


Metaprogramming in D is a really slow thing, there must be faster & simpler ways.
(I think there are simpler ways, using a scripting language to create D code before the compilation. I have created a Python templating system that seem to work well enough for C++).

I have written the following code to test compile time optimization regarding a small kernel convolution, the metaGenerated() is as fast as the hand written version. I show it here because it may be interesting to someone.

But currently the metaGenerated() doesn't work if the kernel2 contains floating point values. I think this problem can be solved with a compile time function/template like ToString that works on floating point values too, do you have it?

Bye,
bearophile


import std.stdio: put = writef, putr = writefln;
import std.metastrings: Format, ToString;
static import std.c.time;

double clock() {
    auto t = std.c.time.clock();
    if (t == -1)
        return 0.0;
    else
        return t/cast(double)std.c.time.CLOCKS_PER_SEC;
}

template Tuple(T...) {
    alias T Tuple;
}

template GenTerm(string m, string x, string y, int nr, int nc, int posx, int posy, ker...) {
    static if (ker[nc * posy + posx] == 0)
        const string GenTerm = "";
    else static if (ker[nc * posy + posx] == 1)
        const string GenTerm = Format!("%s[%s+%s][%s+%s] + ",
                                       m,
                                       x,
                                       ToString!(posx - (nc / 2)),
                                       y,
                                       ToString!(posy - (nr / 2)));
    else
        const string GenTerm = Format!("%s * %s[%s+%s][%s+%s] + ",
                                       ToString!(ker[nc * posy + posx]), //error if ker[] isn't integral
                                       m,
                                       x,
                                       ToString!(posx - (nc / 2)),
                                       y,
                                       ToString!(posy - (nr / 2)));
}

template GenConvolutionLine(string m, string x, string y, int nr, int nc, int posx, int posy, ker...) {
    static if (posx < nc)
        const string GenConvolutionLine = GenTerm!(m, x, y, nr, nc, posx, posy, ker) ~
                                          GenConvolutionLine!(m, x, y, nr, nc, posx+1, posy, ker);
    else
        const string GenConvolutionLine = "";
}

template GenConvolution(string m, string x, string y, int nr, int nc, int posy, ker...) {
    static if (posy < nr)
        const string GenConvolution = GenConvolutionLine!(m, x, y, nr, nc, 0, posy, ker) ~
                                      GenConvolution!(m, x, y, nr, nc, posy+1, ker);
    else
        const string GenConvolution = "0";
}

template Convolution(string m, string x, string y, int nc, ker...) {
    const string Convolution = GenConvolution!(m, x, y, ker.length / nc, nc, 0, ker);
}

// ------------------------------------------------------

void dynamic(float[][] inm, float[][] outm, float[] kern, int w, int h) {
    int height = inm.length;
    int width = inm[0].length;

    for (int x = 1; x < width - 1; ++x)
        for (int y = 1; y < height - 1; ++y) {
            float sum = 0.0;
            for (int i = 0; i < w; ++i)
                for (int j = 0; j < h; ++j)
	                sum += kern[j * w + i] * inm[x + i - w / 2][y + j - h / 2];
            outm[x - 1][y - 1] = sum;
        }
}

void handWritten(float[][] inm, float[][] outm) {
    int height = inm.length;
    int width = inm[0].length;

    for (int x = 1; x < width - 1; ++x)
        for (int y = 1; y < height - 1; ++y)
            outm[x - 1][y - 1] = inm[x+1][y] + inm[x-1][y] + inm[x][y-1] + inm[x][y+1] - 4 * inm[x][y];
}

void metaGenerated(kernel...)(float[][] inm, float[][] outm) {
    int height = inm.length;
    int width = inm[0].length;
    //pragma(msg, Convolution!("inm", "x", "y", 3, kernel)); // to see it

    for (int x = 1; x < width - 1; ++x)
        for (int y = 1; y < height - 1; ++y)
            mixin("outm[x - 1][y - 1] = " ~ Convolution!("inm", "x", "y", 3, kernel) ~ ";");
}

void main() {
    const int WIDTH = 200;
    const int HEIGHT = WIDTH;
    const int NLOOP = 500;

    auto data = new float[][](WIDTH, HEIGHT);
    auto output = new float[][](WIDTH-2, HEIGHT-2);

    for (int j; j < WIDTH; ++j)
        data[j][] = 1.5;

    auto t0 = clock();
    float[] kernel1 = [0, 1, 0, 1, -4, 1, 0, 1, 0];
    for (int i; i < NLOOP; ++i)
        dynamic(data, output, kernel1, 3, 3);

    auto t1 = clock();
    for (int i; i < NLOOP; ++i)
        handWritten(data, output);

    auto t2 = clock();
    alias Tuple!(0, 1, 0, 1, -4, 1, 0, 1, 0) kernel2;
    for (int i; i < NLOOP; ++i)
        metaGenerated!(kernel2)(data, output);

    auto t3 = clock();

    putr("Dynamic       : ", t1 - t0);
    putr("Hand written  : ", t2 - t1);
    putr("Meta-generated: ", t3 - t2);
}


More information about the Digitalmars-d-learn mailing list