float CT stringification
Fawzi Mohamed
fmohamed at mac.com
Thu Jun 5 05:28:55 PDT 2008
On 2008-06-05 12:31:45 +0200, bearophile <bearophileHUGS at lycos.com> said:
> 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?
I wrote an optimized convolution, but only for nearest neighbors in 2D and 3D.
I think that in principle one could generalize it (extending the x
direction is straightforward, the other probably need some work).
Anyway I don't think that you really gain something by making the
weight value compiletime, just the sparsity structure (number of
variables) makes you gain something...
Fawzi
>
> 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