<commit_before>#include <tiramisu/tiramisu.h>
#include <tiramisu/utils.h>
#include "configure.h"

using namespace tiramisu;

Halide::Buffer<float> Hfilter(FOUT_BLOCKING, FIN_BLOCKING, K, K, FIN_NB_BLOCKS, FOUT_NB_BLOCKS);

void gen_random_dense_weights()
{
	srand(1);

	Halide::Buffer<float> Hinput(FIN_BLOCKING, N + 2, N + 2, FIN_NB_BLOCKS, BATCH_SIZE);

	// Initialize buffers
	for (int n = 0; n < BATCH_SIZE; ++n)
		for (int fin = 0; fin < FIn; ++fin)
			for (int y = 0; y < N + 2; ++y)
				for (int x = 0; x < N + 2; ++x)
					Hinput(fin%FIN_BLOCKING, x, y, fin/FIN_BLOCKING, n) = ((float) (rand()%256 - 128)) / 127.f;

	for (int fout = 0; fout < FOut; ++fout)
		for (int fin = 0; fin < FIn; ++fin)
			for (int k_y = 0; k_y < K; ++k_y)
				for (int k_x = 0; k_x < K; ++k_x)
					Hfilter(fout%FOUT_BLOCKING, fin%FIN_BLOCKING, k_x, k_y, fin/FIN_BLOCKING, fout/FOUT_BLOCKING) = ((float)(rand()%256 - 128)) / 127.f;
}

int main(int argc, char **argv)
{
    init("conv_tiramisu");

    gen_random_dense_weights();

    // -------------------------------------------------------
    // Layer I
    // -------------------------------------------------------
    var x("x", 0, N), y("y", 0, N), n("n", 0, BATCH_SIZE);
    var k_x("k_x", 0, K), k_y("k_y", 0, K);

    var fin_b("fin_b", 0, FIN_NB_BLOCKS), ffin("ffin", 0, FIN_BLOCKING);
    var fout_b("fout_b", 0, FOUT_NB_BLOCKS), ffout("ffout", 0, FOUT_BLOCKING);

    var x_pad("x_pad", 0, N + 2), y_pad("y_pad", 0, N + 2);

    input c_input("c_input", {n, fin_b, y_pad, x_pad, ffin}, p_float32);
    input filter("filter", {fout_b, fin_b, k_y, k_x, ffin, ffout}, p_float32);
    input bias("bias", {fout_b, ffout}, p_float32);

    computation conv_init("conv_init", {n, y, fout_b, x, ffout}, bias(fout_b, ffout));
    view conv_out("conv_out", {n, y, fout_b, x, ffout}, p_float32);

    // x_bound is used to have the width dimension divisible by X_BLOCKING
    // in the conv computation.
    var x_bound("x_bound", 0, X_BOUND);
    var x_conclude("x_conclude", X_BOUND, N);

    // Compute unrolled convolution from 0 to x_bound
    computation *unrolled_conv[FOut];
    for (int f0 = 0; f0 < FOUT_NB_BLOCKS; f0++)
      for (int f1 = 0; f1 < FOUT_BLOCKING; f1++)
	{
	    expr e = expr((float) 0);

	    for (int in0 = 0; in0 < FIN_NB_BLOCKS; in0++)
		for (int in1 = 0; in1 < FIN_BLOCKING; in1++)
		    for (int ky = 0; ky < K; ky++)
			for (int kx = 0; kx < K; kx++)
			    if (Hfilter(f1, in1, kx, ky, in0, f0) != 0)
				e = e + expr((float) Hfilter(f1, in1, kx, ky, in0, f0)) * c_input(n, in0, y + ky, x_bound + kx, in1);

	    computation *conv =
			new computation(
			    "conv_" + std::to_string(f0) + "_" + std::to_string(f1),
			    {n, y, x_bound},
				conv_out(n, y, f0, x_bound, f1) + e);

	    conv->get_buffer()->set_auto_allocate(false);
	    unrolled_conv[f0*FOUT_BLOCKING+f1] = conv;
	}

    // Compute convolution from x_bound to N
    computation conv_conclude(
        "conv_conclude",
        {n, y, fout_b, fin_b, k_y, k_x, ffin, ffout, x_conclude},
        conv_out(n, y, fout_b, x_conclude, ffout) + filter(fout_b, fin_b, k_y, k_x, ffin, ffout) * c_input(n, fin_b, y + k_y, x_conclude + k_x, ffin)
    );

    // -------------------------------------------------------
    // Layer II
    // -------------------------------------------------------

    // schedule for conv computation

    // We introduce those two computations to do register blocking
    computation reg_load(
        "reg_load",
        {n, y, fout_b, x_bound, ffout},
        conv_init(n, y, fout_b, x_bound, ffout)
    );

    view conv_orig("conv_orig", {n, y, fout_b, x_bound, ffout}, p_float32);

    computation reg_store(
        "reg_store",
        {n, y, fout_b, x_bound, ffout},
        conv_orig(n, y, fout_b, x_bound, ffout)
    );

    // Split over dimension x
    var x_b, xx;
    reg_load.split(x_bound, X_BLOCKING, x_b, xx);
    for (int f = 0; f < FOut; f++)
	unrolled_conv[f]->split(x_bound, X_BLOCKING, x_b, xx);
    reg_store.split(x_bound, X_BLOCKING, x_b, xx);

    // Interchange
    reg_load.interchange(xx, ffout);
    reg_store.interchange(xx, ffout);

    // Split over dimension fout_b
    var fout_b_up, fout_b_low;
    if (FOUT_B_SPLIT_FACTOR*FOUT_BLOCKING != FOut) {
        reg_load.split(fout_b, FOUT_B_SPLIT_FACTOR, fout_b_up, fout_b_low);
        reg_store.split(fout_b, FOUT_B_SPLIT_FACTOR, fout_b_up, fout_b_low);
    }
    else {
        fout_b_up = y;
        fout_b_low = fout_b;
    }

    reg_load.interchange(fout_b_low, x_b);
    reg_store.interchange(fout_b_low, x_b);

    // Vectorize and unroll
    for (int f = 0; f < FOut; f++)
	{
	    unrolled_conv[f]->tag_vector_level(3, 3);
//	    unrolled_conv[f]->tag_unroll_level(3); //4); //xx);
//	    unrolled_conv[f][in]->tag_vector_level(5, FOUT_BLOCKING); //ffout, FOUT_BLOCKING);
//	    unrolled_conv[f][in]->tag_unroll_level(6); //fout_b_low);
	}
    reg_load.vectorize(ffout, FOUT_BLOCKING);
    reg_store.vectorize(ffout, FOUT_BLOCKING);
    reg_load.tag_unroll_level(xx);
    reg_load.tag_unroll_level(fout_b_low);
    reg_store.tag_unroll_level(xx);
    reg_store.tag_unroll_level(fout_b_low);

    // schedule for conv_conclude
    // This schedule is the same as conv computation
    computation reg_load_conclude(
        "reg_load_conclude",
        {n, y, fout_b, fin_b, ffout, x_conclude},
        conv_init(n, y, fout_b, x_conclude, ffout)
    );

    computation reg_store_conclude(
        "reg_store_conclude",
        {n, y, fout_b, fin_b, ffout, x_conclude},
        conv_conclude(n, y, fout_b, fin_b, 0, 0, 0, ffout, x_conclude)
    );

    // Split over dimension fout_b
    if (FOUT_B_SPLIT_FACTOR*FOUT_BLOCKING != FOut) {
        conv_conclude.split(fout_b, FOUT_B_SPLIT_FACTOR, fout_b_up, fout_b_low);
        reg_load_conclude.split(fout_b, FOUT_B_SPLIT_FACTOR, fout_b_up, fout_b_low);
        reg_store_conclude.split(fout_b, FOUT_B_SPLIT_FACTOR, fout_b_up, fout_b_low);
    }
    else {
        fout_b_up = y;
        fout_b_low = fout_b;
    }

    conv_conclude.interchange(fout_b_low, fin_b);
    conv_conclude.interchange(fout_b_low, k_y);
    conv_conclude.interchange(fout_b_low, k_x);
    conv_conclude.interchange(fout_b_low, ffin);

    reg_load_conclude.interchange(fout_b_low, fin_b);
    reg_store_conclude.interchange(fout_b_low, fin_b);

    // Vectorize and unroll
    reg_load_conclude.vectorize(ffout, FOUT_BLOCKING);
    conv_conclude.vectorize(ffout, FOUT_BLOCKING);
    reg_store_conclude.vectorize(ffout, FOUT_BLOCKING);

    conv_conclude.tag_unroll_level(x_conclude);
    conv_conclude.tag_unroll_level(fout_b_low);

    reg_load_conclude.tag_unroll_level(x_conclude);
    reg_load_conclude.tag_unroll_level(fout_b_low);

    reg_store_conclude.tag_unroll_level(x_conclude);
    reg_store_conclude.tag_unroll_level(fout_b_low);

    // Parallelize and order
//    unrolled_conv[0]->tag_parallel_level(y);
//    unrolled_conv[0]->tag_parallel_level(n);

    conv_init.then(reg_load, fout_b_up);

    computation *previous_comp = &reg_load;

    for (int f = 0; f < FOut; f++)
	{
	    previous_comp->then(*unrolled_conv[f], 2);//4);
	    previous_comp = unrolled_conv[f];
	}

    previous_comp
	    ->then(reg_store, 2) //x_b)
             .then(reg_load_conclude, 1) //fout_b_up)
             .then(conv_conclude, fin_b)
             .then(reg_store_conclude, fin_b);

    // -------------------------------------------------------
    // Layer III
    // -------------------------------------------------------
    buffer conv_buf("conv_buf", {BATCH_SIZE, FOUT_NB_BLOCKS, N, N, FOUT_BLOCKING}, p_float32, a_output);

    // This is where intermediate results of convolution will be stored.
    // We rely on the compiler to detect that this buffer can be mapped to CPU registers.
    buffer reg_buf("reg_buf", {FOUT_B_SPLIT_FACTOR, X_BLOCKING, FOUT_BLOCKING}, p_float32, a_temporary);

    conv_init.store_in(&conv_buf, {n, fout_b, y, x, ffout});
    conv_out.store_in(&reg_buf, {fout_b%FOUT_B_SPLIT_FACTOR, x%X_BLOCKING, ffout});

    reg_load.store_in(&reg_buf, {fout_b%FOUT_B_SPLIT_FACTOR, x_bound%X_BLOCKING, ffout});
    //for (int f = 0; f < FOut; f++)
//	    unrolled_conv[f][in]->store_in(&reg_buf, {fout_b%FOUT_B_SPLIT_FACTOR, x_bound%X_BLOCKING, ffout});
    for (int f0 = 0; f0 < FOUT_NB_BLOCKS; f0++)
      for (int f1 = 0; f1 < FOUT_BLOCKING; f1++)
	   unrolled_conv[f0*FOUT_BLOCKING+f1]->store_in(&reg_buf, {f0%FOUT_B_SPLIT_FACTOR, x_bound%X_BLOCKING, f1});
    conv_orig.store_in(&reg_buf, {fout_b%FOUT_B_SPLIT_FACTOR, x_bound%X_BLOCKING, ffout});
    reg_store.store_in(&conv_buf, {n, fout_b, y, x_bound, ffout});

    reg_load_conclude.store_in(&reg_buf, {fout_b%FOUT_B_SPLIT_FACTOR, x_conclude%X_BLOCKING, ffout});
    conv_conclude.store_in(&reg_buf, {fout_b%FOUT_B_SPLIT_FACTOR, x_conclude%X_BLOCKING, ffout});
    reg_store_conclude.store_in(&conv_buf, {n, fout_b, y, x_conclude, ffout});

    // -------------------------------------------------------
    // Code Generation
    // -------------------------------------------------------
    tiramisu::codegen({
        c_input.get_buffer(),
        filter.get_buffer(),
        bias.get_buffer(),
        &conv_buf
    },"generated_conv_layer.o");

    return 0;
}
<commit_msg>DNN: use unrolled convolution<commit_after>#include <tiramisu/tiramisu.h>
#include <tiramisu/utils.h>
#include "configure.h"

using namespace tiramisu;

Halide::Buffer<float> Hfilter(FOUT_BLOCKING, FIN_BLOCKING, K, K, FIN_NB_BLOCKS, FOUT_NB_BLOCKS);

void gen_random_dense_weights()
{
	srand(1);

	Halide::Buffer<float> Hinput(FIN_BLOCKING, N + 2, N + 2, FIN_NB_BLOCKS, BATCH_SIZE);

	// Initialize buffers
	for (int n = 0; n < BATCH_SIZE; ++n)
		for (int fin = 0; fin < FIn; ++fin)
			for (int y = 0; y < N + 2; ++y)
				for (int x = 0; x < N + 2; ++x)
					Hinput(fin%FIN_BLOCKING, x, y, fin/FIN_BLOCKING, n) = ((float) (rand()%256 - 128)) / 127.f;

	for (int fout = 0; fout < FOut; ++fout)
		for (int fin = 0; fin < FIn; ++fin)
			for (int k_y = 0; k_y < K; ++k_y)
				for (int k_x = 0; k_x < K; ++k_x)
				{
					Hfilter(fout%FOUT_BLOCKING, fin%FIN_BLOCKING, k_x, k_y, fin/FIN_BLOCKING, fout/FOUT_BLOCKING) = ((float)(rand()%256 - 128)) / 127.f;
				}
}

int main(int argc, char **argv)
{
    init("conv_tiramisu");

    gen_random_dense_weights();

    // -------------------------------------------------------
    // Layer I
    // -------------------------------------------------------
    var x("x", 0, N), y("y", 0, N), n("n", 0, BATCH_SIZE);
    var k_x("k_x", 0, K), k_y("k_y", 0, K);

    var fin_b("fin_b", 0, FIN_NB_BLOCKS), ffin("ffin", 0, FIN_BLOCKING);
    var fout_b("fout_b", 0, FOUT_NB_BLOCKS), ffout("ffout", 0, FOUT_BLOCKING);

    var x_pad("x_pad", 0, N + 2), y_pad("y_pad", 0, N + 2);

    input c_input("c_input", {n, fin_b, y_pad, x_pad, ffin}, p_float32);
    input filter("filter", {fout_b, fin_b, k_y, k_x, ffin, ffout}, p_float32);
    input bias("bias", {fout_b, ffout}, p_float32);

    computation conv_init("conv_init", {n, y, fout_b, x, ffout}, bias(fout_b, ffout));
    view conv_out("conv_out", {n, y, fout_b, x, ffout}, p_float32);

    // x_bound is used to have the width dimension divisible by X_BLOCKING
    // in the conv computation.
    var x_bound("x_bound", 0, X_BOUND);
    var x_conclude("x_conclude", X_BOUND, N);

    // Compute unrolled convolution from 0 to x_bound
    computation *unrolled_conv[FOUT_NB_BLOCKS][FOUT_BLOCKING][FIN_NB_BLOCKS][FIN_BLOCKING][K][K];
    for (int in0 = 0; in0 < FIN_NB_BLOCKS; in0++)
      for (int ky = 0; ky < K; ky++)
	for (int kx = 0; kx < K; kx++)
	  for (int in1 = 0; in1 < FIN_BLOCKING; in1++)
    	    for (int f0 = 0; f0 < FOUT_NB_BLOCKS; f0++)
              for (int f1 = 0; f1 < FOUT_BLOCKING; f1++)
	        if (Hfilter(f1, in1, kx, ky, in0, f0) != 0)
		{
		    expr e = expr((float) Hfilter(f1, in1, kx, ky, in0, f0)) * c_input(n, in0, y + ky, x_bound + kx, in1);

		    computation *conv = new computation(
			    "conv_" + std::to_string(f0)  + "_" + std::to_string(f1)  + "_" +
				      std::to_string(in0) + "_" + std::to_string(in1) + "_" +
				      std::to_string(ky) +  "_" + std::to_string(kx),
			    {n, y, x_bound}, conv_out(n, y, f0, x_bound, f1) + e);

		    conv->get_buffer()->set_auto_allocate(false);
		    unrolled_conv[f0][f1][in0][in1][ky][kx] = conv;
		}
		else
		    unrolled_conv[f0][f1][in0][in1][ky][kx] = NULL;

    // Compute convolution from x_bound to N
#if DO_CONCLUSION
    computation conv_conclude(
        "conv_conclude",
        {n, y, fout_b, fin_b, k_y, k_x, ffin, ffout, x_conclude},
        conv_out(n, y, fout_b, x_conclude, ffout) + filter(fout_b, fin_b, k_y, k_x, ffin, ffout) * c_input(n, fin_b, y + k_y, x_conclude + k_x, ffin)
    );
#endif

    // -------------------------------------------------------
    // Layer II
    // -------------------------------------------------------

    // schedule for conv computation

    // We introduce those two computations to do register blocking
    computation reg_load(
        "reg_load",
        {n, y, fout_b, x_bound, ffout},
        conv_init(n, y, fout_b, x_bound, ffout)
    );

    view conv_orig("conv_orig", {n, y, fout_b, x_bound, ffout}, p_float32);

    computation reg_store(
        "reg_store",
        {n, y, fout_b, x_bound, ffout},
        conv_orig(n, y, fout_b, x_bound, ffout)
    );

    // Split over dimension x
    var x_b, xx;
    reg_load.split(x_bound, X_BLOCKING, x_b, xx);
    for (int f0 = 0; f0 < FOUT_NB_BLOCKS; f0++)
      for (int f1 = 0; f1 < FOUT_BLOCKING; f1++)
        for (int in0 = 0; in0 < FIN_NB_BLOCKS; in0++)
	  for (int in1 = 0; in1 < FIN_BLOCKING; in1++)
	    for (int ky = 0; ky < K; ky++)
	      for (int kx = 0; kx < K; kx++)
		if (unrolled_conv[f0][f1][in0][in1][ky][kx] != NULL)
		    unrolled_conv[f0][f1][in0][in1][ky][kx]->split(x_bound, X_BLOCKING, x_b, xx);
    reg_store.split(x_bound, X_BLOCKING, x_b, xx);

    // Interchange
    reg_load.interchange(xx, ffout);
    reg_store.interchange(xx, ffout);

    // Split over dimension fout_b
    var fout_b_up, fout_b_low;
    if (FOUT_B_SPLIT_FACTOR*FOUT_BLOCKING != FOut) {
        reg_load.split(fout_b, FOUT_B_SPLIT_FACTOR, fout_b_up, fout_b_low);
        reg_store.split(fout_b, FOUT_B_SPLIT_FACTOR, fout_b_up, fout_b_low);
    }
    else {
        fout_b_up = y;
        fout_b_low = fout_b;
    }

    reg_load.interchange(fout_b_low, x_b);
    reg_store.interchange(fout_b_low, x_b);

    // This is where intermediate results of convolution will be stored.
    // We rely on the compiler to detect that this buffer can be mapped to CPU registers.
    buffer reg_buf("reg_buf", {FOUT_B_SPLIT_FACTOR, X_BLOCKING, FOUT_BLOCKING}, p_float32, a_temporary);
    reg_buf.set_auto_allocate(false);
    computation *alloc_reg_buf = reg_buf.allocate_at(reg_load, x_b);

    // Vectorize and unroll
    for (int f0 = 0; f0 < FOUT_NB_BLOCKS; f0++)
      for (int f1 = 0; f1 < FOUT_BLOCKING; f1++)
        for (int in0 = 0; in0 < FIN_NB_BLOCKS; in0++)
	  for (int in1 = 0; in1 < FIN_BLOCKING; in1++)
	    for (int ky = 0; ky < K; ky++)
	      for (int kx = 0; kx < K; kx++)
		if (unrolled_conv[f0][f1][in0][in1][ky][kx] != NULL)
		    unrolled_conv[f0][f1][in0][in1][ky][kx]->tag_vector_level(3, 8);

    reg_load.vectorize(ffout, FOUT_BLOCKING);
    reg_store.vectorize(ffout, FOUT_BLOCKING);
    reg_load.tag_unroll_level(xx);
    reg_load.tag_unroll_level(fout_b_low);
    reg_store.tag_unroll_level(xx);
    reg_store.tag_unroll_level(fout_b_low);

#if DO_CONCLUSION
    // schedule for conv_conclude
    // This schedule is the same as conv computation
    computation reg_load_conclude(
        "reg_load_conclude",
        {n, y, fout_b, fin_b, ffout, x_conclude},
        conv_init(n, y, fout_b, x_conclude, ffout)
    );

    computation reg_store_conclude(
        "reg_store_conclude",
        {n, y, fout_b, fin_b, ffout, x_conclude},
        conv_conclude(n, y, fout_b, fin_b, 0, 0, 0, ffout, x_conclude)
    );

    // Split over dimension fout_b
    if (FOUT_B_SPLIT_FACTOR*FOUT_BLOCKING != FOut) {
        conv_conclude.split(fout_b, FOUT_B_SPLIT_FACTOR, fout_b_up, fout_b_low);
        reg_load_conclude.split(fout_b, FOUT_B_SPLIT_FACTOR, fout_b_up, fout_b_low);
        reg_store_conclude.split(fout_b, FOUT_B_SPLIT_FACTOR, fout_b_up, fout_b_low);
    }
    else {
        fout_b_up = y;
        fout_b_low = fout_b;
    }

    conv_conclude.interchange(fout_b_low, fin_b);
    conv_conclude.interchange(fout_b_low, k_y);
    conv_conclude.interchange(fout_b_low, k_x);
    conv_conclude.interchange(fout_b_low, ffin);

    reg_load_conclude.interchange(fout_b_low, fin_b);
    reg_store_conclude.interchange(fout_b_low, fin_b);

    // Vectorize and unroll
    reg_load_conclude.vectorize(ffout, FOUT_BLOCKING);
    conv_conclude.vectorize(ffout, FOUT_BLOCKING);
    reg_store_conclude.vectorize(ffout, FOUT_BLOCKING);

    conv_conclude.tag_unroll_level(x_conclude);
    conv_conclude.tag_unroll_level(fout_b_low);

    reg_load_conclude.tag_unroll_level(x_conclude);
    reg_load_conclude.tag_unroll_level(fout_b_low);

    reg_store_conclude.tag_unroll_level(x_conclude);
    reg_store_conclude.tag_unroll_level(fout_b_low);
#endif

    // Parallelize and order
    unrolled_conv[0][0][0][0][0][0]->tag_parallel_level(y);
    unrolled_conv[0][0][0][0][0][0]->tag_parallel_level(n);

    conv_init.then(*alloc_reg_buf, fout_b_up)
	     .then(reg_load, x_b);

    computation *previous_comp = &reg_load;

    for (int in0 = 0; in0 < FIN_NB_BLOCKS; in0++)
      for (int ky = 0; ky < K; ky++)
	for (int kx = 0; kx < K; kx++)
	  for (int in1 = 0; in1 < FIN_BLOCKING; in1++)
    	    for (int f0 = 0; f0 < FOUT_NB_BLOCKS; f0++)
              for (int f1 = 0; f1 < FOUT_BLOCKING; f1++)
		if (unrolled_conv[f0][f1][in0][in1][ky][kx] != NULL)
		{
		    previous_comp->then(*unrolled_conv[f0][f1][in0][in1][ky][kx], 2);
		    previous_comp = unrolled_conv[f0][f1][in0][in1][ky][kx];
		}

    previous_comp
	    ->then(reg_store, 2);

#if DO_CONCLUSION
    reg_store.then(reg_load_conclude, 1)
             .then(conv_conclude, fin_b)
             .then(reg_store_conclude, fin_b);
#endif

    // -------------------------------------------------------
    // Layer III
    // -------------------------------------------------------
    buffer conv_buf("conv_buf", {BATCH_SIZE, FOUT_NB_BLOCKS, N, N, FOUT_BLOCKING}, p_float32, a_output);

    conv_init.store_in(&conv_buf, {n, fout_b, y, x, ffout});
    conv_out.store_in(&reg_buf, {fout_b%FOUT_B_SPLIT_FACTOR, x%X_BLOCKING, ffout});

    reg_load.store_in(&reg_buf, {fout_b%FOUT_B_SPLIT_FACTOR, x_bound%X_BLOCKING, ffout});

    for (int f0 = 0; f0 < FOUT_NB_BLOCKS; f0++)
      for (int f1 = 0; f1 < FOUT_BLOCKING; f1++)
        for (int in0 = 0; in0 < FIN_NB_BLOCKS; in0++)
	  for (int in1 = 0; in1 < FIN_BLOCKING; in1++)
	    for (int ky = 0; ky < K; ky++)
	      for (int kx = 0; kx < K; kx++)
		if (unrolled_conv[f0][f1][in0][in1][ky][kx] != NULL)
		{
		    unrolled_conv[f0][f1][in0][in1][ky][kx]->store_in(&reg_buf, {f0%FOUT_B_SPLIT_FACTOR, x_bound%X_BLOCKING, f1});
		}

    conv_orig.store_in(&reg_buf, {fout_b%FOUT_B_SPLIT_FACTOR, x_bound%X_BLOCKING, ffout});
    reg_store.store_in(&conv_buf, {n, fout_b, y, x_bound, ffout});

#if DO_CONCLUSION
    reg_load_conclude.store_in(&reg_buf, {fout_b%FOUT_B_SPLIT_FACTOR, x_conclude%X_BLOCKING, ffout});
    conv_conclude.store_in(&reg_buf, {fout_b%FOUT_B_SPLIT_FACTOR, x_conclude%X_BLOCKING, ffout});
    reg_store_conclude.store_in(&conv_buf, {n, fout_b, y, x_conclude, ffout});
#endif

    // -------------------------------------------------------
    // Code Generation
    // -------------------------------------------------------
    tiramisu::codegen({
        c_input.get_buffer(),
        filter.get_buffer(),
        bias.get_buffer(),
        &conv_buf
    },"generated_conv_layer.o");

    return 0;
}
<|endoftext|>


<commit_before>#include <Arduino.h>

#include "state_search.h"

#include "settings.h"
#include "settings_internal.h"
#include "settings_eeprom.h"
#include "receiver.h"
#include "channels.h"
#include "buttons.h"
#include "ui.h"

#include "pstr_helper.h"

enum class ScanDirection : int8_t {
    UP = 1,
    DOWN = -1
};

static bool manual = false;
static bool scanning = true;
static ScanDirection direction = ScanDirection::UP;
static bool forceNext = false;
static uint8_t orderedChanelIndex = 0;

static bool scanningPeak = false;
static uint8_t peakChannelIndex = 0;
#define PEAK_LOOKAHEAD 4
static uint8_t peaks[PEAK_LOOKAHEAD] = { 0 };

static void onUpdateAuto();
static void onUpdateManual();

void StateMachine::SearchStateHandler::onUpdate() {
    Receiver::waitForStableRssi();

    if (!manual) {
        onUpdateAuto();
    }

    Ui::needUpdate();
}

static void onUpdateAuto() {
    if (scanningPeak) {
        uint8_t peaksIndex = peakChannelIndex - orderedChanelIndex;
        peaks[peaksIndex] = Receiver::rssiA;
        peakChannelIndex++;

        if (peaksIndex >= PEAK_LOOKAHEAD || peakChannelIndex >= CHANNELS_SIZE) {
            uint8_t largestPeak = 0;
            uint8_t largestPeakIndex = 0;
            for (uint8_t i = 0; i < PEAK_LOOKAHEAD; i++) {
                uint8_t peak = peaks[i];
                if (peak > largestPeak) {
                    largestPeak = peak;
                    largestPeakIndex = i;
                }
            }

            uint8_t peakChannel = orderedChanelIndex + largestPeakIndex;
            orderedChanelIndex = peakChannel;
            Receiver::setChannel(Channels::getOrderedIndex(peakChannel));

            scanningPeak = false;
        } else {
            Receiver::setChannel(Channels::getOrderedIndex(peakChannelIndex));
        }
    } else {
        if (scanning) {
            if (!forceNext && Receiver::rssiA >= RSSI_SEEK_TRESHOLD) {
                scanning = false;
                scanningPeak = true;
                peakChannelIndex = orderedChanelIndex;

                for (uint8_t i = 0; i < PEAK_LOOKAHEAD; i++)
                    peaks[i] = 0;
            } else {
                orderedChanelIndex += static_cast<int8_t>(direction);
                if (orderedChanelIndex == 255)
                    orderedChanelIndex = CHANNELS_SIZE - 1;
                else if (orderedChanelIndex >= CHANNELS_SIZE)
                    orderedChanelIndex = 0;

                Receiver::setChannel(
                    Channels::getOrderedIndex(orderedChanelIndex));

                if (forceNext)
                    forceNext = false;
            }
        }
    }
}

static void onUpdateManual() {

}

void StateMachine::SearchStateHandler::onButtonChange() {
    if (Buttons::get(Button::MODE)->pressed) {
        manual = !manual;
    }

    if (manual) {
        if (Buttons::get(Button::UP)->pressed) {
            orderedChanelIndex += 1;
        } else if (Buttons::get(Button::DOWN)->pressed) {
            orderedChanelIndex -= 1;
        }

        if (orderedChanelIndex == 255)
            orderedChanelIndex = CHANNELS_SIZE - 1;
        else if (orderedChanelIndex >= CHANNELS_SIZE)
            orderedChanelIndex = 0;

        Receiver::setChannel(Channels::getOrderedIndex(orderedChanelIndex));
    } else {
        if (Buttons::get(Button::UP)->pressed) {
            scanning = true;
            forceNext = true;
            direction = ScanDirection::UP;
        } else if (Buttons::get(Button::DOWN)->pressed) {
            scanning = true;
            forceNext = true;
            direction = ScanDirection::DOWN;
        }
    }
}

static void drawBorders();
static void drawChannelText();
static void drawFrequencyText();
static void drawScanBar();
static void drawRssiGraph();

void StateMachine::SearchStateHandler::onInitialDraw() {
    Ui::clear();

    drawBorders();

    drawChannelText();
    drawFrequencyText();
    drawScanBar();
    drawRssiGraph();

    Ui::needDisplay();
}

void StateMachine::SearchStateHandler::onUpdateDraw() {
    Ui::clearRect(
        0,
        0,
        59,
        CHAR_HEIGHT * 5
    );

    Ui::clearRect(
        0,
        SCREEN_HEIGHT - (CHAR_HEIGHT * 2),
        59,
        CHAR_HEIGHT * 2
    );

    Ui::clearRect(
        1,
        (CHAR_HEIGHT * 5) + 4 + 1,
        54,
        5
    );

    drawChannelText();
    drawFrequencyText();
    drawScanBar();
    drawRssiGraph();

    /*Ui::display.setTextSize(1);
    Ui::display.setTextColor(WHITE);

    char channelName[3];
    Channels::getName(Receiver::activeChannel, channelName);

    Ui::display.setCursor(0, 0);
    Ui::display.print(channelName[0]);
    Ui::display.setCursor(0, CHAR_HEIGHT + 1);
    Ui::display.print(channelName[1]);

    String freq = String(Channels::getFrequency(Receiver::activeChannel));
    Ui::display.setCursor(0, SCREEN_HEIGHT - ((CHAR_HEIGHT + 1) * 4) + 1);
    Ui::display.print(freq.charAt(0));
    Ui::display.setCursor(0, SCREEN_HEIGHT - ((CHAR_HEIGHT + 1) * 3) + 1);
    Ui::display.print(freq.charAt(1));
    Ui::display.setCursor(0, SCREEN_HEIGHT - ((CHAR_HEIGHT + 1) * 2) + 1);
    Ui::display.print(freq.charAt(2));
    Ui::display.setCursor(0, SCREEN_HEIGHT - ((CHAR_HEIGHT + 1) * 1) + 1);
    Ui::display.print(freq.charAt(3));

    Ui::display.drawFastVLine(CHAR_WIDTH + 1, 0, SCREEN_HEIGHT, WHITE);
    Ui::display.drawFastHLine(0, (CHAR_HEIGHT + 1) * 2, CHAR_WIDTH + 1, WHITE);
    Ui::display.drawFastHLine(0, ((CHAR_HEIGHT + 1) * 4) - 2, CHAR_WIDTH + 1, WHITE);

    uint8_t barMaxHeight = (((CHAR_HEIGHT + 1) * 4) - 2) - ((CHAR_HEIGHT + 1) * 2) - 2;
    uint8_t barHeight = orderedChanelIndex * barMaxHeight / CHANNELS_SIZE;
    Ui::display.fillRect(0, (CHAR_HEIGHT + 1) * 2 + 2, CHAR_WIDTH, barHeight, WHITE);

    Ui::drawDashedHLine(CHAR_WIDTH + 2, 32, SCREEN_WIDTH - (CHAR_WIDTH + 2), 8);

    Ui::drawGraph(
        Receiver::rssiALast,
        RECEIVER_LAST_DATA_SIZE,
        100,
        CHAR_WIDTH + 2,
        0,
        SCREEN_WIDTH - (CHAR_WIDTH + 2),
        30
    );

    Ui::drawGraph(
        Receiver::rssiBLast,
        RECEIVER_LAST_DATA_SIZE,
        100,
        CHAR_WIDTH + 2,
        SCREEN_HEIGHT - 30,
        SCREEN_WIDTH - (CHAR_WIDTH + 2),
        30
    );*/

    Ui::needDisplay();
}

static void drawBorders() {
    Ui::display.drawFastVLine(59, 0, SCREEN_HEIGHT, WHITE);
    Ui::display.drawFastVLine(SCREEN_WIDTH - 1, 0, SCREEN_HEIGHT, WHITE);

    Ui::display.drawRoundRect(
        0,
        (CHAR_HEIGHT * 5) + 4,
        56,
        7,
        2,
        WHITE
    );
}

static void drawChannelText() {
    Ui::display.setTextSize(5);
    Ui::display.setTextColor(WHITE);
    Ui::display.setCursor(0, 0);

    Ui::display.print(Channels::getName(Receiver::activeChannel));
}

static void drawFrequencyText() {
    Ui::display.setTextSize(2);
    Ui::display.setTextColor(WHITE);
    Ui::display.setCursor(6, SCREEN_HEIGHT - (CHAR_HEIGHT * 2));

    Ui::display.print(Channels::getFrequency(Receiver::activeChannel));
}

static void drawScanBar() {
    uint8_t scanWidth = orderedChanelIndex * 54 / CHANNELS_SIZE;

    Ui::display.fillRect(
        1,
        (CHAR_HEIGHT * 5) + 4 + 1,
        scanWidth,
        5,
        WHITE
    );
}

static void drawRssiGraph() {
    Ui::drawGraph(
        Receiver::rssiALast,
        RECEIVER_LAST_DATA_SIZE,
        100,
        62,
        0,
        66,
        30
    );

    Ui::drawGraph(
        Receiver::rssiBLast,
        RECEIVER_LAST_DATA_SIZE,
        100,
        62,
        34,
        66,
        30
    );

    Ui::drawDashedHLine(60, 32, 64, 8);

    if (Receiver::activeReceiver == RECEIVER_A) {
        Ui::display.fillRoundRect(
            59,
            7,
            CHAR_WIDTH * 2 + 2 + 2,
            32 - 7 - 7,
            2,
            WHITE
        );
    } else {
        Ui::display.fillRoundRect(
            59,
            7,
            CHAR_WIDTH * 2 + 2 + 2,
            32 - 7 - 7,
            2,
            BLACK
        );

        Ui::display.drawRoundRect(
            59,
            7,
            CHAR_WIDTH * 2 + 2 + 2,
            32 - 7 - 7,
            2,
            WHITE
        );
    }

    if (Receiver::activeReceiver == RECEIVER_B) {
        Ui::display.fillRoundRect(
            59,
            32 + 7,
            CHAR_WIDTH * 2 + 2 + 2,
            32 - 7 - 7,
            2,
            WHITE
        );
    } else {
        Ui::display.fillRoundRect(
            59,
            7,
            CHAR_WIDTH * 2 + 2 + 2,
            32 - 7 - 7,
            2,
            BLACK
        );

        Ui::display.drawRoundRect(
            59,
            32 + 7,
            CHAR_WIDTH * 2 + 2 + 2,
            32 - 7 - 7,
            2,
            WHITE
        );
    }

    Ui::display.setTextColor(INVERSE);

    Ui::display.setCursor(61, 16 - CHAR_HEIGHT);
    Ui::display.print(PSTR2("A"));

    Ui::display.setCursor(61, 48 - CHAR_HEIGHT);
    Ui::display.print(PSTR2("B"));
}
<commit_msg>Fix wrong diversity indicator on search<commit_after>#include <Arduino.h>

#include "state_search.h"

#include "settings.h"
#include "settings_internal.h"
#include "settings_eeprom.h"
#include "receiver.h"
#include "channels.h"
#include "buttons.h"
#include "ui.h"

#include "pstr_helper.h"

enum class ScanDirection : int8_t {
    UP = 1,
    DOWN = -1
};

static bool manual = false;
static bool scanning = true;
static ScanDirection direction = ScanDirection::UP;
static bool forceNext = false;
static uint8_t orderedChanelIndex = 0;

static bool scanningPeak = false;
static uint8_t peakChannelIndex = 0;
#define PEAK_LOOKAHEAD 4
static uint8_t peaks[PEAK_LOOKAHEAD] = { 0 };

static void onUpdateAuto();
static void onUpdateManual();

void StateMachine::SearchStateHandler::onUpdate() {
    Receiver::waitForStableRssi();

    if (!manual) {
        onUpdateAuto();
    }

    Ui::needUpdate();
}

static void onUpdateAuto() {
    if (scanningPeak) {
        uint8_t peaksIndex = peakChannelIndex - orderedChanelIndex;
        peaks[peaksIndex] = Receiver::rssiA;
        peakChannelIndex++;

        if (peaksIndex >= PEAK_LOOKAHEAD || peakChannelIndex >= CHANNELS_SIZE) {
            uint8_t largestPeak = 0;
            uint8_t largestPeakIndex = 0;
            for (uint8_t i = 0; i < PEAK_LOOKAHEAD; i++) {
                uint8_t peak = peaks[i];
                if (peak > largestPeak) {
                    largestPeak = peak;
                    largestPeakIndex = i;
                }
            }

            uint8_t peakChannel = orderedChanelIndex + largestPeakIndex;
            orderedChanelIndex = peakChannel;
            Receiver::setChannel(Channels::getOrderedIndex(peakChannel));

            scanningPeak = false;
        } else {
            Receiver::setChannel(Channels::getOrderedIndex(peakChannelIndex));
        }
    } else {
        if (scanning) {
            if (!forceNext && Receiver::rssiA >= RSSI_SEEK_TRESHOLD) {
                scanning = false;
                scanningPeak = true;
                peakChannelIndex = orderedChanelIndex;

                for (uint8_t i = 0; i < PEAK_LOOKAHEAD; i++)
                    peaks[i] = 0;
            } else {
                orderedChanelIndex += static_cast<int8_t>(direction);
                if (orderedChanelIndex == 255)
                    orderedChanelIndex = CHANNELS_SIZE - 1;
                else if (orderedChanelIndex >= CHANNELS_SIZE)
                    orderedChanelIndex = 0;

                Receiver::setChannel(
                    Channels::getOrderedIndex(orderedChanelIndex));

                if (forceNext)
                    forceNext = false;
            }
        }
    }
}

static void onUpdateManual() {

}

void StateMachine::SearchStateHandler::onButtonChange() {
    if (Buttons::get(Button::MODE)->pressed) {
        manual = !manual;
    }

    if (manual) {
        if (Buttons::get(Button::UP)->pressed) {
            orderedChanelIndex += 1;
        } else if (Buttons::get(Button::DOWN)->pressed) {
            orderedChanelIndex -= 1;
        }

        if (orderedChanelIndex == 255)
            orderedChanelIndex = CHANNELS_SIZE - 1;
        else if (orderedChanelIndex >= CHANNELS_SIZE)
            orderedChanelIndex = 0;

        Receiver::setChannel(Channels::getOrderedIndex(orderedChanelIndex));
    } else {
        if (Buttons::get(Button::UP)->pressed) {
            scanning = true;
            forceNext = true;
            direction = ScanDirection::UP;
        } else if (Buttons::get(Button::DOWN)->pressed) {
            scanning = true;
            forceNext = true;
            direction = ScanDirection::DOWN;
        }
    }
}

static void drawBorders();
static void drawChannelText();
static void drawFrequencyText();
static void drawScanBar();
static void drawRssiGraph();

void StateMachine::SearchStateHandler::onInitialDraw() {
    Ui::clear();

    drawBorders();

    drawChannelText();
    drawFrequencyText();
    drawScanBar();
    drawRssiGraph();

    Ui::needDisplay();
}

void StateMachine::SearchStateHandler::onUpdateDraw() {
    Ui::clearRect(
        0,
        0,
        59,
        CHAR_HEIGHT * 5
    );

    Ui::clearRect(
        0,
        SCREEN_HEIGHT - (CHAR_HEIGHT * 2),
        59,
        CHAR_HEIGHT * 2
    );

    Ui::clearRect(
        1,
        (CHAR_HEIGHT * 5) + 4 + 1,
        54,
        5
    );

    drawChannelText();
    drawFrequencyText();
    drawScanBar();
    drawRssiGraph();

    /*Ui::display.setTextSize(1);
    Ui::display.setTextColor(WHITE);

    char channelName[3];
    Channels::getName(Receiver::activeChannel, channelName);

    Ui::display.setCursor(0, 0);
    Ui::display.print(channelName[0]);
    Ui::display.setCursor(0, CHAR_HEIGHT + 1);
    Ui::display.print(channelName[1]);

    String freq = String(Channels::getFrequency(Receiver::activeChannel));
    Ui::display.setCursor(0, SCREEN_HEIGHT - ((CHAR_HEIGHT + 1) * 4) + 1);
    Ui::display.print(freq.charAt(0));
    Ui::display.setCursor(0, SCREEN_HEIGHT - ((CHAR_HEIGHT + 1) * 3) + 1);
    Ui::display.print(freq.charAt(1));
    Ui::display.setCursor(0, SCREEN_HEIGHT - ((CHAR_HEIGHT + 1) * 2) + 1);
    Ui::display.print(freq.charAt(2));
    Ui::display.setCursor(0, SCREEN_HEIGHT - ((CHAR_HEIGHT + 1) * 1) + 1);
    Ui::display.print(freq.charAt(3));

    Ui::display.drawFastVLine(CHAR_WIDTH + 1, 0, SCREEN_HEIGHT, WHITE);
    Ui::display.drawFastHLine(0, (CHAR_HEIGHT + 1) * 2, CHAR_WIDTH + 1, WHITE);
    Ui::display.drawFastHLine(0, ((CHAR_HEIGHT + 1) * 4) - 2, CHAR_WIDTH + 1, WHITE);

    uint8_t barMaxHeight = (((CHAR_HEIGHT + 1) * 4) - 2) - ((CHAR_HEIGHT + 1) * 2) - 2;
    uint8_t barHeight = orderedChanelIndex * barMaxHeight / CHANNELS_SIZE;
    Ui::display.fillRect(0, (CHAR_HEIGHT + 1) * 2 + 2, CHAR_WIDTH, barHeight, WHITE);

    Ui::drawDashedHLine(CHAR_WIDTH + 2, 32, SCREEN_WIDTH - (CHAR_WIDTH + 2), 8);

    Ui::drawGraph(
        Receiver::rssiALast,
        RECEIVER_LAST_DATA_SIZE,
        100,
        CHAR_WIDTH + 2,
        0,
        SCREEN_WIDTH - (CHAR_WIDTH + 2),
        30
    );

    Ui::drawGraph(
        Receiver::rssiBLast,
        RECEIVER_LAST_DATA_SIZE,
        100,
        CHAR_WIDTH + 2,
        SCREEN_HEIGHT - 30,
        SCREEN_WIDTH - (CHAR_WIDTH + 2),
        30
    );*/

    Ui::needDisplay();
}

static void drawBorders() {
    Ui::display.drawFastVLine(59, 0, SCREEN_HEIGHT, WHITE);
    Ui::display.drawFastVLine(SCREEN_WIDTH - 1, 0, SCREEN_HEIGHT, WHITE);

    Ui::display.drawRoundRect(
        0,
        (CHAR_HEIGHT * 5) + 4,
        56,
        7,
        2,
        WHITE
    );
}

static void drawChannelText() {
    Ui::display.setTextSize(5);
    Ui::display.setTextColor(WHITE);
    Ui::display.setCursor(0, 0);

    Ui::display.print(Channels::getName(Receiver::activeChannel));
}

static void drawFrequencyText() {
    Ui::display.setTextSize(2);
    Ui::display.setTextColor(WHITE);
    Ui::display.setCursor(6, SCREEN_HEIGHT - (CHAR_HEIGHT * 2));

    Ui::display.print(Channels::getFrequency(Receiver::activeChannel));
}

static void drawScanBar() {
    uint8_t scanWidth = orderedChanelIndex * 54 / CHANNELS_SIZE;

    Ui::display.fillRect(
        1,
        (CHAR_HEIGHT * 5) + 4 + 1,
        scanWidth,
        5,
        WHITE
    );
}

static void drawRssiGraph() {
    Ui::drawGraph(
        Receiver::rssiALast,
        RECEIVER_LAST_DATA_SIZE,
        100,
        62,
        0,
        66,
        30
    );

    Ui::drawGraph(
        Receiver::rssiBLast,
        RECEIVER_LAST_DATA_SIZE,
        100,
        62,
        34,
        66,
        30
    );

    Ui::drawDashedHLine(60, 32, 64, 8);

    if (Receiver::activeReceiver == RECEIVER_A) {
        Ui::display.fillRoundRect(
            59,
            7,
            CHAR_WIDTH * 2 + 2 + 2,
            32 - 7 - 7,
            2,
            WHITE
        );
    } else {
        Ui::display.fillRoundRect(
            59,
            7,
            CHAR_WIDTH * 2 + 2 + 2,
            32 - 7 - 7,
            2,
            BLACK
        );

        Ui::display.drawRoundRect(
            59,
            7,
            CHAR_WIDTH * 2 + 2 + 2,
            32 - 7 - 7,
            2,
            WHITE
        );
    }

    if (Receiver::activeReceiver == RECEIVER_B) {
        Ui::display.fillRoundRect(
            59,
            32 + 7,
            CHAR_WIDTH * 2 + 2 + 2,
            32 - 7 - 7,
            2,
            WHITE
        );
    } else {
        Ui::display.fillRoundRect(
            59,
            32 + 7,
            CHAR_WIDTH * 2 + 2 + 2,
            32 - 7 - 7,
            2,
            BLACK
        );

        Ui::display.drawRoundRect(
            59,
            32 + 7,
            CHAR_WIDTH * 2 + 2 + 2,
            32 - 7 - 7,
            2,
            WHITE
        );
    }

    Ui::display.setTextColor(INVERSE);

    Ui::display.setCursor(61, 16 - CHAR_HEIGHT);
    Ui::display.print(PSTR2("A"));

    Ui::display.setCursor(61, 48 - CHAR_HEIGHT);
    Ui::display.print(PSTR2("B"));
}
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2009, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */

#include <gtest/gtest.h>

#include <pcl/point_types.h>
#include <pcl/features/normal_3d.h>
#include <pcl/features/integral_image_normal.h>

#include <iostream>

using namespace pcl;
using namespace std;

typedef search::KdTree<PointXYZ>::Ptr KdTreePtr;
PointCloud<PointXYZ> cloud;
KdTreePtr tree;

NormalEstimation<PointXYZ, Normal> n;
IntegralImageNormalEstimation<PointXYZ, Normal> ne;

TEST(PCL, IntegralImage)
{
  const unsigned width = 640;
  const unsigned height = 480;
  const unsigned max_window_size = 11;
  IntegralImage2Dim<float,1> integral_image(true);

  // test for dense data with elementstride = 1
  float* data = new float[width * height];
  for(unsigned yIdx = 0; yIdx < height; ++yIdx)
  {
    for(unsigned xIdx = 0; xIdx < width; ++xIdx)
    {
      data[width * yIdx + xIdx] = 1;
    }
  }
  integral_image.setInput (data, width, height, 1, width);

  for (unsigned window_width = 2; window_width < max_window_size; ++window_width)
  {
    for (unsigned window_height = 2; window_height < max_window_size; ++window_height)
    {
      for(unsigned yIdx = 0; yIdx < height - window_height; ++yIdx)
      {
        for(unsigned xIdx = 0; xIdx < width - window_width; ++xIdx)
        {
          //std::cout << xIdx << " , " << yIdx << " - " << window_width << " x " << window_height << " : " << integral_image.getFirstOrderSum (xIdx, yIdx, window_width, window_height)[0] << std::endl;
          EXPECT_EQ (window_width * window_height, integral_image.getFirstOrderSum (xIdx, yIdx, window_width, window_height)[0]);
        }
      }
    }
  }
  delete[] data;

  //now test with element-stride 2
  unsigned element_stride = 2;
  unsigned row_stride = width * element_stride;
  data = new float[row_stride * height];
  for(unsigned yIdx = 0; yIdx < height; ++yIdx)
  {
    for(unsigned xIdx = 0; xIdx < row_stride; xIdx += element_stride)
    {
      data[row_stride * yIdx + xIdx] = 1;
      data[row_stride * yIdx + xIdx + 1] = -1;
    }
  }
  integral_image.setInput (data, width, height, element_stride, row_stride);
  for (unsigned window_width = 1; window_width < max_window_size; ++window_width)
  {
    for (unsigned window_height = 1; window_height < max_window_size; ++window_height)
    {
      for(unsigned yIdx = 0; yIdx < height - window_height; ++yIdx)
      {
        for(unsigned xIdx = 0; xIdx < width - window_width; ++xIdx)
        {
          //std::cout << xIdx << " , " << yIdx << " - " << window_width << " x " << window_height << " : " << integral_image.getFirstOrderSum (xIdx, yIdx, window_width, window_height)[0] << std::endl;
          EXPECT_EQ (window_width * window_height, integral_image.getFirstOrderSum (xIdx, yIdx, window_width, window_height)[0]);
        }
      }
    }
  }
  delete[] data;

  //now test with odd element-stride 3 and modulo-uneven row_stride
  element_stride = 3;
  row_stride = width * element_stride + 1;
  data = new float[row_stride * height];
  for(unsigned yIdx = 0; yIdx < height; ++yIdx)
  {
    for(unsigned xIdx = 0; xIdx < row_stride; xIdx += element_stride)
    {
      data[row_stride * yIdx + xIdx] = 1;
      data[row_stride * yIdx + xIdx + 1] = 2;
      data[row_stride * yIdx + xIdx + 2] = xIdx;
    }
  }
  integral_image.setInput (data, width, height, element_stride, row_stride);
  for (unsigned window_width = 1; window_width < max_window_size; ++window_width)
  {
    for (unsigned window_height = 1; window_height < max_window_size; ++window_height)
    {
      for(unsigned yIdx = 0; yIdx < height - window_height; ++yIdx)
      {
        for(unsigned xIdx = 0; xIdx < width - window_width; ++xIdx)
        {
          EXPECT_EQ (window_width * window_height, integral_image.getFirstOrderSum (xIdx, yIdx, window_width, window_height)[0]);
          EXPECT_EQ (window_width * window_height, integral_image.getSecondOrderSum (xIdx, yIdx, window_width, window_height)[0]);
//std::cout << xIdx << " , " << yIdx << " - " << window_width << " x " << window_height << " : " << integral_image.getSecondOrderSum (xIdx, yIdx, window_width, window_height)[0] << std::endl;
        }
      }
    }
  }
  delete[] data;

  // now test multidimensional case with 3D but element_stride = 4 and row_stride non-dividable by element_stride
  IntegralImage2Dim<float, 3> integral_image3(true);
  element_stride = 4;
  row_stride = width * element_stride + 1;
  data = new float[row_stride * height];
  for(unsigned yIdx = 0; yIdx < height; ++yIdx)
  {
    for(unsigned xIdx = 0; xIdx < width; ++xIdx)
    {
      data[row_stride * yIdx + xIdx * element_stride] = xIdx;
      data[row_stride * yIdx + xIdx * element_stride + 1] = yIdx;
      data[row_stride * yIdx + xIdx * element_stride + 2] = xIdx + yIdx;
    }
  }
  integral_image3.setInput (data, width, height, element_stride, row_stride);
  for (unsigned window_width = 1; window_width < max_window_size; ++window_width)
  {
    for (unsigned window_height = 1; window_height < max_window_size; ++window_height)
    {
      for(unsigned yIdx = 0; yIdx < height - window_height; ++yIdx)
      {
        for(unsigned xIdx = 0; xIdx < width - window_width; ++xIdx)
        {
          IntegralImage2Dim<float, 3>::ElementType sum = integral_image3.getFirstOrderSum (xIdx, yIdx, window_width, window_height);

          EXPECT_EQ (window_height * window_width * (window_width + 2 * xIdx - 1), sum[0] * 2);
          EXPECT_EQ (window_width * window_height * (window_height + 2 * yIdx - 1), sum[1] * 2);
          EXPECT_EQ (window_width * window_height * (window_height + 2 * yIdx - 1) + window_height * window_width * (window_width + 2 * xIdx - 1), sum[2] * 2);

          IntegralImage2Dim<float, 3>::SecondOrderType sumSqr = integral_image3.getSecondOrderSum (xIdx, yIdx, window_width, window_height);

          IntegralImage2Dim<float, 3>::SecondOrderType ground_truth;
          ground_truth.setZero ();
          for (unsigned wy = yIdx; wy < yIdx + window_height; ++wy)
          {
            for (unsigned wx = xIdx; wx < xIdx + window_width; ++wx)
            {
              float* val = data + (wy * row_stride + wx * element_stride);
              //ground_truth[0] += val[0] * val[0];
              ground_truth[1] += val[0] * val[1];
              ground_truth[2] += val[0] * val[2];
              //ground_truth[3] += val[1] * val[1];
              ground_truth[4] += val[1] * val[2];
              ground_truth[5] += val[2] * val[2];
            }
          }

          //EXPECT_EQ (ground_truth [0], sumSqr[0]);
          EXPECT_EQ (ground_truth [1], sumSqr[1]);
          EXPECT_EQ (ground_truth [2], sumSqr[2]);
          //EXPECT_EQ (ground_truth [3], sumSqr[3]);
          EXPECT_EQ (ground_truth [4], sumSqr[4]);
          EXPECT_EQ (ground_truth [5], sumSqr[5]);

          int w = window_width + xIdx - 1;
          long result = w * (w + 1) * (2*w + 1) - xIdx * (xIdx - 1) * (2*xIdx - 1);

          EXPECT_EQ (window_height * result, sumSqr[0] * 6);

          int h = window_height + yIdx - 1;
          result = h * (h + 1) * (2*h + 1) - yIdx * (yIdx - 1) * (2*yIdx - 1);
          EXPECT_EQ (window_width * result, sumSqr[3] * 6);
        }
      }
    }
  }
  delete[] data;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST (PCL, NormalEstimation)
{
  tree.reset (new search::KdTree<PointXYZ> (false));
  n.setSearchMethod (tree);
  n.setKSearch (10);

  n.setInputCloud (cloud.makeShared ());

  PointCloud<Normal> output;
  n.compute (output);

  EXPECT_EQ (output.points.size (), cloud.points.size ());
  EXPECT_EQ (output.width, cloud.width);
  EXPECT_EQ (output.height, cloud.height);

  for (size_t i = 0; i < cloud.points.size (); ++i)
  {
    EXPECT_NEAR (fabs (output.points[i].normal_x),   0, 1e-2);
    EXPECT_NEAR (fabs (output.points[i].normal_y),   0, 1e-2);
    EXPECT_NEAR (fabs (output.points[i].normal_z), 1.0, 1e-2);
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST (PCL, IINormalEstimation)
{
  Normal normal;
  ne.setInputCloud (cloud.makeShared ());
  ne.setRectSize (2, 2);
  ne.computePointNormal (160, 120, normal);
  ne.setNormalEstimationMethod (ne.COVARIANCE_MATRIX);

  EXPECT_NEAR (fabs (normal.normal_x),   0, 1e-2);
  EXPECT_NEAR (fabs (normal.normal_y),   0, 1e-2);
  EXPECT_NEAR (fabs (normal.normal_z), 1.0, 1e-2);

  PointCloud<Normal> output;
  ne.compute (output);

  EXPECT_EQ (output.points.size (), cloud.points.size ());
  EXPECT_EQ (output.width, cloud.width);
  EXPECT_EQ (output.height, cloud.height);

  for (size_t v = 0; v < cloud.height; ++v)
  {
    for (size_t u = 0; u < cloud.width; ++u)
    {
      if (!pcl_isfinite(output (u, v).normal_x) &&
          !pcl_isfinite(output (u, v).normal_y) &&
          !pcl_isfinite(output (u, v).normal_z))
        continue;

      EXPECT_NEAR (fabs (output (u, v).normal_x),   0, 1e-2);
      EXPECT_NEAR (fabs (output (u, v).normal_y),   0, 1e-2);
      EXPECT_NEAR (fabs (output (u, v).normal_z), 1.0, 1e-2);
    }
  }
  EXPECT_NEAR (fabs (output (160, 120).normal_x),   0, 1e-2);
  EXPECT_NEAR (fabs (output (160, 120).normal_y),   0, 1e-2);
  EXPECT_NEAR (fabs (output (160, 120).normal_z), 1.0, 1e-2);

  ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT);
  ne.compute (output);

  EXPECT_EQ (output.points.size (), cloud.points.size ());
  EXPECT_EQ (output.width, cloud.width);
  EXPECT_EQ (output.height, cloud.height);

  for (size_t v = 0; v < cloud.height; ++v)
  {
    for (size_t u = 0; u < cloud.width; ++u)
    {
      if (!pcl_isfinite(output (u, v).normal_x) &&
          !pcl_isfinite(output (u, v).normal_y) &&
          !pcl_isfinite(output (u, v).normal_z))
        continue;

      EXPECT_NEAR (fabs (output (u, v).normal_x),   0, 1e-2);
      EXPECT_NEAR (fabs (output (u, v).normal_y),   0, 1e-2);
      EXPECT_NEAR (fabs (output (u, v).normal_z), 1.0, 1e-2);
    }
  }
}

/* ---[ */
int
main (int argc, char** argv)
{
  cloud.points.resize (320 * 240);
  cloud.width = 320;
  cloud.height = 240;
  cloud.is_dense = true;
  for (size_t v = 0; v < cloud.height; ++v)
  {
    for (size_t u = 0; u < cloud.width; ++u)
    {
      cloud (u, v).x = u;
      cloud (u, v).y = v;
      cloud (u, v).z = 10;
    }
  }

  testing::InitGoogleTest (&argc, argv);
  return (RUN_ALL_TESTS ());

  return 1;
}
/* ]--- */

<commit_msg>fix a crash in test_ii_normals.cpp<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2009, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */

#include <gtest/gtest.h>

#include <pcl/point_types.h>
#include <pcl/features/normal_3d.h>
#include <pcl/features/integral_image_normal.h>

#include <iostream>

using namespace pcl;
using namespace std;

typedef search::KdTree<PointXYZ>::Ptr KdTreePtr;
PointCloud<PointXYZ> cloud;
KdTreePtr tree;

NormalEstimation<PointXYZ, Normal> n;
IntegralImageNormalEstimation<PointXYZ, Normal> ne;

TEST(PCL, IntegralImage)
{
  const unsigned width = 640;
  const unsigned height = 480;
  const unsigned max_window_size = 11;
  IntegralImage2Dim<float,1> integral_image(true);

  // test for dense data with elementstride = 1
  float* data = new float[width * height];
  for(unsigned yIdx = 0; yIdx < height; ++yIdx)
  {
    for(unsigned xIdx = 0; xIdx < width; ++xIdx)
    {
      data[width * yIdx + xIdx] = 1;
    }
  }
  integral_image.setInput (data, width, height, 1, width);

  for (unsigned window_width = 2; window_width < max_window_size; ++window_width)
  {
    for (unsigned window_height = 2; window_height < max_window_size; ++window_height)
    {
      for(unsigned yIdx = 0; yIdx < height - window_height; ++yIdx)
      {
        for(unsigned xIdx = 0; xIdx < width - window_width; ++xIdx)
        {
          //std::cout << xIdx << " , " << yIdx << " - " << window_width << " x " << window_height << " : " << integral_image.getFirstOrderSum (xIdx, yIdx, window_width, window_height)[0] << std::endl;
          EXPECT_EQ (window_width * window_height, integral_image.getFirstOrderSum (xIdx, yIdx, window_width, window_height)[0]);
        }
      }
    }
  }
  delete[] data;

  //now test with element-stride 2
  unsigned element_stride = 2;
  unsigned row_stride = width * element_stride;
  data = new float[row_stride * height];
  for(unsigned yIdx = 0; yIdx < height; ++yIdx)
  {
    for(unsigned xIdx = 0; xIdx < row_stride; xIdx += element_stride)
    {
      data[row_stride * yIdx + xIdx] = 1;
      data[row_stride * yIdx + xIdx + 1] = -1;
    }
  }
  integral_image.setInput (data, width, height, element_stride, row_stride);
  for (unsigned window_width = 1; window_width < max_window_size; ++window_width)
  {
    for (unsigned window_height = 1; window_height < max_window_size; ++window_height)
    {
      for(unsigned yIdx = 0; yIdx < height - window_height; ++yIdx)
      {
        for(unsigned xIdx = 0; xIdx < width - window_width; ++xIdx)
        {
          //std::cout << xIdx << " , " << yIdx << " - " << window_width << " x " << window_height << " : " << integral_image.getFirstOrderSum (xIdx, yIdx, window_width, window_height)[0] << std::endl;
          EXPECT_EQ (window_width * window_height, integral_image.getFirstOrderSum (xIdx, yIdx, window_width, window_height)[0]);
        }
      }
    }
  }
  delete[] data;

  //now test with odd element-stride 3 and modulo-uneven row_stride
  element_stride = 3;
  row_stride = width * element_stride;
  data = new float[row_stride * height];
  for(unsigned yIdx = 0; yIdx < height; ++yIdx)
  {
    for(unsigned xIdx = 0; xIdx < row_stride; xIdx += element_stride)
    {
      data[row_stride * yIdx + xIdx] = 1;
      data[row_stride * yIdx + xIdx + 1] = 2;
      data[row_stride * yIdx + xIdx + 2] = xIdx;
    }
  }
  integral_image.setInput (data, width, height, element_stride, row_stride);
  for (unsigned window_width = 1; window_width < max_window_size; ++window_width)
  {
    for (unsigned window_height = 1; window_height < max_window_size; ++window_height)
    {
      for(unsigned yIdx = 0; yIdx < height - window_height; ++yIdx)
      {
        for(unsigned xIdx = 0; xIdx < width - window_width; ++xIdx)
        {
          EXPECT_EQ (window_width * window_height, integral_image.getFirstOrderSum (xIdx, yIdx, window_width, window_height)[0]);
          EXPECT_EQ (window_width * window_height, integral_image.getSecondOrderSum (xIdx, yIdx, window_width, window_height)[0]);
//std::cout << xIdx << " , " << yIdx << " - " << window_width << " x " << window_height << " : " << integral_image.getSecondOrderSum (xIdx, yIdx, window_width, window_height)[0] << std::endl;
        }
      }
    }
  }
  delete[] data;

  // now test multidimensional case with 3D but element_stride = 4 and row_stride non-dividable by element_stride
  IntegralImage2Dim<float, 3> integral_image3(true);
  element_stride = 4;
  row_stride = width * element_stride;
  data = new float[row_stride * height];
  for(unsigned yIdx = 0; yIdx < height; ++yIdx)
  {
    for(unsigned xIdx = 0; xIdx < width; ++xIdx)
    {
      data[row_stride * yIdx + xIdx * element_stride] = xIdx;
      data[row_stride * yIdx + xIdx * element_stride + 1] = yIdx;
      data[row_stride * yIdx + xIdx * element_stride + 2] = xIdx + yIdx;
    }
  }
  integral_image3.setInput (data, width, height, element_stride, row_stride);
  for (unsigned window_width = 1; window_width < max_window_size; ++window_width)
  {
    for (unsigned window_height = 1; window_height < max_window_size; ++window_height)
    {
      for(unsigned yIdx = 0; yIdx < height - window_height; ++yIdx)
      {
        for(unsigned xIdx = 0; xIdx < width - window_width; ++xIdx)
        {
          IntegralImage2Dim<float, 3>::ElementType sum = integral_image3.getFirstOrderSum (xIdx, yIdx, window_width, window_height);

          EXPECT_EQ (window_height * window_width * (window_width + 2 * xIdx - 1), sum[0] * 2);
          EXPECT_EQ (window_width * window_height * (window_height + 2 * yIdx - 1), sum[1] * 2);
          EXPECT_EQ (window_width * window_height * (window_height + 2 * yIdx - 1) + window_height * window_width * (window_width + 2 * xIdx - 1), sum[2] * 2);

          IntegralImage2Dim<float, 3>::SecondOrderType sumSqr = integral_image3.getSecondOrderSum (xIdx, yIdx, window_width, window_height);

          IntegralImage2Dim<float, 3>::SecondOrderType ground_truth;
          ground_truth.setZero ();
          for (unsigned wy = yIdx; wy < yIdx + window_height; ++wy)
          {
            for (unsigned wx = xIdx; wx < xIdx + window_width; ++wx)
            {
              float* val = data + (wy * row_stride + wx * element_stride);
              //ground_truth[0] += val[0] * val[0];
              ground_truth[1] += val[0] * val[1];
              ground_truth[2] += val[0] * val[2];
              //ground_truth[3] += val[1] * val[1];
              ground_truth[4] += val[1] * val[2];
              ground_truth[5] += val[2] * val[2];
            }
          }

          //EXPECT_EQ (ground_truth [0], sumSqr[0]);
          EXPECT_EQ (ground_truth [1], sumSqr[1]);
          EXPECT_EQ (ground_truth [2], sumSqr[2]);
          //EXPECT_EQ (ground_truth [3], sumSqr[3]);
          EXPECT_EQ (ground_truth [4], sumSqr[4]);
          EXPECT_EQ (ground_truth [5], sumSqr[5]);

          int w = window_width + xIdx - 1;
          long result = w * (w + 1) * (2*w + 1) - xIdx * (xIdx - 1) * (2*xIdx - 1);

          EXPECT_EQ (window_height * result, sumSqr[0] * 6);

          int h = window_height + yIdx - 1;
          result = h * (h + 1) * (2*h + 1) - yIdx * (yIdx - 1) * (2*yIdx - 1);
          EXPECT_EQ (window_width * result, sumSqr[3] * 6);
        }
      }
    }
  }
  delete[] data;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST (PCL, NormalEstimation)
{
  tree.reset (new search::KdTree<PointXYZ> (false));
  n.setSearchMethod (tree);
  n.setKSearch (10);

  n.setInputCloud (cloud.makeShared ());

  PointCloud<Normal> output;
  n.compute (output);

  EXPECT_EQ (output.points.size (), cloud.points.size ());
  EXPECT_EQ (output.width, cloud.width);
  EXPECT_EQ (output.height, cloud.height);

  for (size_t i = 0; i < cloud.points.size (); ++i)
  {
    EXPECT_NEAR (fabs (output.points[i].normal_x),   0, 1e-2);
    EXPECT_NEAR (fabs (output.points[i].normal_y),   0, 1e-2);
    EXPECT_NEAR (fabs (output.points[i].normal_z), 1.0, 1e-2);
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TEST (PCL, IINormalEstimation)
{
  Normal normal;
  ne.setInputCloud (cloud.makeShared ());
  ne.setRectSize (2, 2);
  ne.computePointNormal (160, 120, normal);
  ne.setNormalEstimationMethod (ne.COVARIANCE_MATRIX);

  EXPECT_NEAR (fabs (normal.normal_x),   0, 1e-2);
  EXPECT_NEAR (fabs (normal.normal_y),   0, 1e-2);
  EXPECT_NEAR (fabs (normal.normal_z), 1.0, 1e-2);

  PointCloud<Normal> output;
  ne.compute (output);

  EXPECT_EQ (output.points.size (), cloud.points.size ());
  EXPECT_EQ (output.width, cloud.width);
  EXPECT_EQ (output.height, cloud.height);

  for (size_t v = 0; v < cloud.height; ++v)
  {
    for (size_t u = 0; u < cloud.width; ++u)
    {
      if (!pcl_isfinite(output (u, v).normal_x) &&
          !pcl_isfinite(output (u, v).normal_y) &&
          !pcl_isfinite(output (u, v).normal_z))
        continue;

      EXPECT_NEAR (fabs (output (u, v).normal_x),   0, 1e-2);
      EXPECT_NEAR (fabs (output (u, v).normal_y),   0, 1e-2);
      EXPECT_NEAR (fabs (output (u, v).normal_z), 1.0, 1e-2);
    }
  }
  EXPECT_NEAR (fabs (output (160, 120).normal_x),   0, 1e-2);
  EXPECT_NEAR (fabs (output (160, 120).normal_y),   0, 1e-2);
  EXPECT_NEAR (fabs (output (160, 120).normal_z), 1.0, 1e-2);

  ne.setNormalEstimationMethod (ne.AVERAGE_3D_GRADIENT);
  ne.compute (output);

  EXPECT_EQ (output.points.size (), cloud.points.size ());
  EXPECT_EQ (output.width, cloud.width);
  EXPECT_EQ (output.height, cloud.height);

  for (size_t v = 0; v < cloud.height; ++v)
  {
    for (size_t u = 0; u < cloud.width; ++u)
    {
      if (!pcl_isfinite(output (u, v).normal_x) &&
          !pcl_isfinite(output (u, v).normal_y) &&
          !pcl_isfinite(output (u, v).normal_z))
        continue;

      EXPECT_NEAR (fabs (output (u, v).normal_x),   0, 1e-2);
      EXPECT_NEAR (fabs (output (u, v).normal_y),   0, 1e-2);
      EXPECT_NEAR (fabs (output (u, v).normal_z), 1.0, 1e-2);
    }
  }
}

/* ---[ */
int
main (int argc, char** argv)
{
  cloud.points.resize (320 * 240);
  cloud.width = 320;
  cloud.height = 240;
  cloud.is_dense = true;
  for (size_t v = 0; v < cloud.height; ++v)
  {
    for (size_t u = 0; u < cloud.width; ++u)
    {
      cloud (u, v).x = u;
      cloud (u, v).y = v;
      cloud (u, v).z = 10;
    }
  }

  testing::InitGoogleTest (&argc, argv);
  return (RUN_ALL_TESTS ());

  return 1;
}
/* ]--- */

<|endoftext|>


<commit_before>/**
 * Test: Checks the correctness of the library when used by multiple threads.
 */
#include <riff/riff.hpp>

#include <stdio.h>
#include <unistd.h>
#include <omp.h>

#define CHNAME "ipc:///tmp/demo.ipc"

#define ITERATIONS 10000
#define NUM_THREADS 1
#ifndef TOLERANCE
#define TOLERANCE 0.1 // Between 0 and 1
#endif
#define CUSTOM_VALUE_0 2
#define CUSTOM_VALUE_1 5

// In microseconds
#define IDLE_TIME 1000
#define LATENCY 3000
#define MONITORING_INTERVAL 1000000

class DemoAggregator: public riff::Aggregator{
public:
    double aggregate(size_t index, const std::vector<double>& customValues){
        double r = 0;
        for(double d : customValues){
            r += d;
        }
        return r;
    }
};

int main(int argc, char** argv){
    if(argc < 2){
        std::cerr << "Usage: " << argv[0] << " [0(Monitor) or 1(Application)]" << std::endl;
        return -1;
    }
    if(atoi(argv[1]) == 0){
        riff::Monitor mon(CHNAME);
        std::cout << "[[Monitor]]: Waiting application start." << std::endl;
        mon.waitStart();
        std::cout << "[[Monitor]]: Application started." << std::endl;
        riff::ApplicationSample sample;
        usleep(MONITORING_INTERVAL);
        while(mon.getSample(sample)){
            std::cout << "Received sample: " << sample << std::endl;

            double expectedLatency = LATENCY*1000; // To nanoseconds
            double expectedUtilization = ((double)LATENCY / ((double) (IDLE_TIME + LATENCY))) * 100;
            if(abs(expectedLatency - sample.latency)/(double) expectedLatency > TOLERANCE){
                std::cerr << "Expected latency: " << expectedLatency <<
                             " Actual latency: " << sample.latency << std::endl;
                return -1;
            }
            if(abs(expectedUtilization - sample.loadPercentage)/(double) expectedUtilization > TOLERANCE){
                std::cerr << "Expected utilization: " << expectedUtilization <<
                             " Actual utilization: " << sample.loadPercentage << std::endl;
                return -1;
            }
            // We do not check anymore the number of task since when sampling is applied,
            // it is higly variable, i.e. we could miss a bunch of tasks.
            // Bandwidth and latency must still be correct nevertheless.

            // We need enough long monitoring interval to store at least once
            // per thread each custom value.
            if(MONITORING_INTERVAL > NUM_THREADS*(IDLE_TIME+LATENCY)){
                if(sample.customFields[0] != CUSTOM_VALUE_0 * NUM_THREADS){
                    std::cerr << "Expected custom 0: " << CUSTOM_VALUE_0 * NUM_THREADS <<
                                 " Actual custom 0: " << sample.customFields[0] << std::endl;
                    return -1;
                }
                if(sample.customFields[1] != CUSTOM_VALUE_1 * NUM_THREADS){
                    std::cerr << "Expected custom 1: " << CUSTOM_VALUE_1 * NUM_THREADS <<
                                 " Actual custom 1: " << sample.customFields[1] << std::endl;
                    return -1;
                }
            }else{
                std::cerr << "Impossible to assess correctness of custom values. Use a longer monitoring interval." << std::endl;
                return -1;
            }
            usleep(MONITORING_INTERVAL);
        }
        uint expectedExecutionTime = ((ITERATIONS*(IDLE_TIME+LATENCY))/(double)NUM_THREADS) / 1000; // Microseconds to milliseconds
        if(abs(expectedExecutionTime - mon.getExecutionTime())/expectedExecutionTime > TOLERANCE){
            std::cerr << "Expected execution time: " << expectedExecutionTime <<
                         " Actual execution time: " << mon.getExecutionTime() << std::endl;
            return -1;
        }
    }else{
        // Application. Use omp just to test the correctness when multiple
        // threads call begin/end.
        omp_set_num_threads(NUM_THREADS);
        riff::Application app(CHNAME, NUM_THREADS, new DemoAggregator());
        //std::cout << "[[Application]] Created." << std::endl;
#pragma omp parallel for
        for(size_t i = 0; i < ITERATIONS; i++){
            int threadId = omp_get_thread_num();
            //std::cout << "[[Application]] Receiving." << std::endl;
            usleep(IDLE_TIME);
            //std::cout << "[[Application]] Computing." << std::endl;
            app.begin(threadId);
            usleep(LATENCY);
            //std::cout << "[[Application]] Computed." << std::endl;
            app.storeCustomValue(0, CUSTOM_VALUE_0, threadId);
            app.storeCustomValue(1, CUSTOM_VALUE_1, threadId);
            app.end(threadId);
        }
        app.terminate();
    }
    return 0;
}
<commit_msg>[FIX] Few CMake things.<commit_after>/**
 * Test: Checks the correctness of the library when used by multiple threads.
 */
#include <riff/riff.hpp>

#include <stdio.h>
#include <unistd.h>
#include <omp.h>

#define CHNAME "ipc:///tmp/demo.ipc"

#define ITERATIONS 1000
#define NUM_THREADS 1
#ifndef TOLERANCE
#define TOLERANCE 0.1 // Between 0 and 1
#endif
#define CUSTOM_VALUE_0 2
#define CUSTOM_VALUE_1 5

// In microseconds
#define IDLE_TIME 10000
#define LATENCY 30000
#define MONITORING_INTERVAL 1000000

class DemoAggregator: public riff::Aggregator{
public:
    double aggregate(size_t index, const std::vector<double>& customValues){
        double r = 0;
        for(double d : customValues){
            r += d;
        }
        return r;
    }
};

int main(int argc, char** argv){
    if(argc < 2){
        std::cerr << "Usage: " << argv[0] << " [0(Monitor) or 1(Application)]" << std::endl;
        return -1;
    }
    if(atoi(argv[1]) == 0){
        riff::Monitor mon(CHNAME);
        std::cout << "[[Monitor]]: Waiting application start." << std::endl;
        mon.waitStart();
        std::cout << "[[Monitor]]: Application started." << std::endl;
        riff::ApplicationSample sample;
        usleep(MONITORING_INTERVAL);
        while(mon.getSample(sample)){
            std::cout << "Received sample: " << sample << std::endl;

            double expectedLatency = LATENCY*1000; // To nanoseconds
            double expectedUtilization = ((double)LATENCY / ((double) (IDLE_TIME + LATENCY))) * 100;
            if(abs(expectedLatency - sample.latency)/(double) expectedLatency > TOLERANCE){
                std::cerr << "Expected latency: " << expectedLatency <<
                             " Actual latency: " << sample.latency << std::endl;
                return -1;
            }
            if(abs(expectedUtilization - sample.loadPercentage)/(double) expectedUtilization > TOLERANCE){
                std::cerr << "Expected utilization: " << expectedUtilization <<
                             " Actual utilization: " << sample.loadPercentage << std::endl;
                return -1;
            }
            // We do not check anymore the number of task since when sampling is applied,
            // it is higly variable, i.e. we could miss a bunch of tasks.
            // Bandwidth and latency must still be correct nevertheless.

            // We need enough long monitoring interval to store at least once
            // per thread each custom value.
            if(MONITORING_INTERVAL > NUM_THREADS*(IDLE_TIME+LATENCY)){
                if(sample.customFields[0] != CUSTOM_VALUE_0 * NUM_THREADS){
                    std::cerr << "Expected custom 0: " << CUSTOM_VALUE_0 * NUM_THREADS <<
                                 " Actual custom 0: " << sample.customFields[0] << std::endl;
                    return -1;
                }
                if(sample.customFields[1] != CUSTOM_VALUE_1 * NUM_THREADS){
                    std::cerr << "Expected custom 1: " << CUSTOM_VALUE_1 * NUM_THREADS <<
                                 " Actual custom 1: " << sample.customFields[1] << std::endl;
                    return -1;
                }
            }else{
                std::cerr << "Impossible to assess correctness of custom values. Use a longer monitoring interval." << std::endl;
                return -1;
            }
            usleep(MONITORING_INTERVAL);
        }
        uint expectedExecutionTime = ((ITERATIONS*(IDLE_TIME+LATENCY))/(double)NUM_THREADS) / 1000; // Microseconds to milliseconds
        if(abs(expectedExecutionTime - mon.getExecutionTime())/expectedExecutionTime > TOLERANCE){
            std::cerr << "Expected execution time: " << expectedExecutionTime <<
                         " Actual execution time: " << mon.getExecutionTime() << std::endl;
            return -1;
        }
    }else{
        // Application. Use omp just to test the correctness when multiple
        // threads call begin/end.
        omp_set_num_threads(NUM_THREADS);
        riff::Application app(CHNAME, NUM_THREADS, new DemoAggregator());
        //std::cout << "[[Application]] Created." << std::endl;
#pragma omp parallel for
        for(size_t i = 0; i < ITERATIONS; i++){
            int threadId = omp_get_thread_num();
            //std::cout << "[[Application]] Receiving." << std::endl;
            usleep(IDLE_TIME);
            //std::cout << "[[Application]] Computing." << std::endl;
            app.begin(threadId);
            usleep(LATENCY);
            //std::cout << "[[Application]] Computed." << std::endl;
            app.storeCustomValue(0, CUSTOM_VALUE_0, threadId);
            app.storeCustomValue(1, CUSTOM_VALUE_1, threadId);
            app.end(threadId);
        }
        app.terminate();
    }
    return 0;
}
<|endoftext|>


<commit_before>#include <fgt/fgt.hpp>

#include <armadillo>
#include <gtest/gtest.h>

namespace fgt {

class Trial : public ::testing::TestWithParam<double> {
protected:
    static const arma::uword NumSourceRows = 1000;
    static const arma::uword NumTargetRows = 1000;
    static const arma::uword NumCols = 3;
    constexpr static const double Epsilon = 1e-2;

    Trial()
        : ::testing::TestWithParam<double>(),
          m_source(arma::randu<arma::mat>(NumSourceRows, NumCols)),
          m_target(arma::randu<arma::mat>(NumTargetRows, NumCols)),
          m_weights(arma::randu<arma::vec>(NumSourceRows)),
          m_weights_sum(arma::accu(m_weights)),
          m_epsilon(Epsilon) {}

    arma::mat m_source, m_target;
    arma::vec m_weights;
    double m_weights_sum;
    double m_epsilon;
};

TEST_P(Trial, AllMethods) {
    Direct direct(m_source, GetParam());
    arma::vec g_direct = direct.compute(m_target, m_weights);

    Ifgt ifgt(m_source, GetParam(), m_epsilon);
    arma::vec g_ifgt = ifgt.compute(m_source, m_weights);

    double error_ifgt = arma::max(arma::abs(g_ifgt - g_direct) / m_weights_sum);
    EXPECT_GT(m_epsilon, error_ifgt);
}

INSTANTIATE_TEST_CASE_P(Trial, Trial,
                        ::testing::Values(0.01, 0.02, 0.04, 0.08, 0.16, 0.32,
                                          0.64));
}
<commit_msg>Dumb reversal bug in the trial<commit_after>#include <fgt/fgt.hpp>

#include <armadillo>
#include <gtest/gtest.h>

namespace fgt {

class Trial : public ::testing::TestWithParam<double> {
protected:
    static const arma::uword NumSourceRows = 1000;
    static const arma::uword NumTargetRows = 1000;
    static const arma::uword NumCols = 3;
    constexpr static const double Epsilon = 1e-2;

    Trial()
        : ::testing::TestWithParam<double>(),
          m_source(arma::randu<arma::mat>(NumSourceRows, NumCols)),
          m_target(arma::randu<arma::mat>(NumTargetRows, NumCols)),
          m_weights(arma::randu<arma::vec>(NumSourceRows)),
          m_weights_sum(arma::sum(m_weights)),
          m_epsilon(Epsilon) {}

    arma::mat m_source, m_target;
    arma::vec m_weights;
    double m_weights_sum;
    double m_epsilon;
};

TEST_P(Trial, AllMethods) {
    Direct direct(m_source, GetParam());
    arma::vec g_direct = direct.compute(m_target, m_weights);

    Ifgt ifgt(m_source, GetParam(), m_epsilon);
    arma::vec g_ifgt = ifgt.compute(m_target, m_weights);

    double error_ifgt = arma::max(arma::abs(g_ifgt - g_direct) / m_weights_sum);
    EXPECT_GT(m_epsilon, error_ifgt);
}

INSTANTIATE_TEST_CASE_P(Trial, Trial,
                        ::testing::Values(0.01, 0.02, 0.04, 0.08, 0.16, 0.32,
                                          0.64));
}
<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

/*
   This is some wisdom from Cygnus's web page.  If you just try to use
   the "stringify" operator on a preprocessor directive, you'd get
   "PLATFORM", not "Intel Linux" (or whatever the value of PLATFORM
   is).  That's because the stringify operator is a special case, and
   the preprocessor isn't allowed to expand things that are passed to
   it.  However, by defining two layers of macros, you get the right
   behavior, since the first pass converts:

   xstr(PLATFORM) -> str(Intel Linux)

   and the next pass gives:

   str(Intel Linux) -> "Intel Linux"

   This is exactly what we want, so we use it.  -Derek Wright and Jeff
   Ballard, 12/2/99

   Also, because the NT build system is totally different, we have to
   define the correct platform string right in here. :( -Derek 12/3/99
*/

#include "condor_common.h"

#define xstr(s) str(s)
#define str(s) #s

#if defined(WIN32)
#define PLATFORM INTEL-WINNT50
#endif

/* Via configure, one may have specified a particular buildid string to use
	in the version string. So honor that request here. */
#if defined(BUILDID)
#define BUILDIDSTR " BuildID: " xstr(BUILDID)
#else
#define BUILDIDSTR ""
#endif

/* Here is the version string - update before a public release */
/* --- IMPORTANT!  THE FORMAT OF THE VERSION STRING IS VERY STRICT
   BECAUSE IT IS PARSED AT RUNTIME AND COMPILE-TIME.  DO NOT ALTER THE
   FORMAT OR ENTER ANYTHING EXTRA BEFORE THE DATE.  IF YOU WISH TO ADD
   EXTRA INFORMATION, DO SO _AFTER_ THE BUILDIDSTR AND BEFORE THE TRAILING
   '$' CHARACTER.
   EXAMPLES:
       $CondorVersion: 6.9.5 " __DATE__ BUILDIDSTR " WinNTPreview $ [OK]
	   $CondorVersion: 6.9.5 WinNTPreview " __DATE__ BUILDIDSTR " $ [WRONG!!!]
   Any questions?  See Todd or Derek.  Note: if you mess it up, DaemonCore
   will EXCEPT at startup time.
*/

static char* CondorVersionString = "$CondorVersion: 7.4.1 " __DATE__ BUILDIDSTR " PRE-RELEASE $";

/* Here is the platform string.  You don't need to edit this */
static char* CondorPlatformString = "$CondorPlatform: " xstr(PLATFORM) " $";

extern "C" {

const char*
CondorVersion( void )
{
	return CondorVersionString;
}

const char*
CondorPlatform( void )
{
	return CondorPlatformString;
}

} /* extern "C" */

<commit_msg>updated CondorVersion in V7_4-branch to be 7.4.2 PRE-RELEASE<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

/*
   This is some wisdom from Cygnus's web page.  If you just try to use
   the "stringify" operator on a preprocessor directive, you'd get
   "PLATFORM", not "Intel Linux" (or whatever the value of PLATFORM
   is).  That's because the stringify operator is a special case, and
   the preprocessor isn't allowed to expand things that are passed to
   it.  However, by defining two layers of macros, you get the right
   behavior, since the first pass converts:

   xstr(PLATFORM) -> str(Intel Linux)

   and the next pass gives:

   str(Intel Linux) -> "Intel Linux"

   This is exactly what we want, so we use it.  -Derek Wright and Jeff
   Ballard, 12/2/99

   Also, because the NT build system is totally different, we have to
   define the correct platform string right in here. :( -Derek 12/3/99
*/

#include "condor_common.h"

#define xstr(s) str(s)
#define str(s) #s

#if defined(WIN32)
#define PLATFORM INTEL-WINNT50
#endif

/* Via configure, one may have specified a particular buildid string to use
	in the version string. So honor that request here. */
#if defined(BUILDID)
#define BUILDIDSTR " BuildID: " xstr(BUILDID)
#else
#define BUILDIDSTR ""
#endif

/* Here is the version string - update before a public release */
/* --- IMPORTANT!  THE FORMAT OF THE VERSION STRING IS VERY STRICT
   BECAUSE IT IS PARSED AT RUNTIME AND COMPILE-TIME.  DO NOT ALTER THE
   FORMAT OR ENTER ANYTHING EXTRA BEFORE THE DATE.  IF YOU WISH TO ADD
   EXTRA INFORMATION, DO SO _AFTER_ THE BUILDIDSTR AND BEFORE THE TRAILING
   '$' CHARACTER.
   EXAMPLES:
       $CondorVersion: 6.9.5 " __DATE__ BUILDIDSTR " WinNTPreview $ [OK]
	   $CondorVersion: 6.9.5 WinNTPreview " __DATE__ BUILDIDSTR " $ [WRONG!!!]
   Any questions?  See Todd or Derek.  Note: if you mess it up, DaemonCore
   will EXCEPT at startup time.
*/

static char* CondorVersionString = "$CondorVersion: 7.4.2 " __DATE__ BUILDIDSTR " PRE-RELEASE $";

/* Here is the platform string.  You don't need to edit this */
static char* CondorPlatformString = "$CondorPlatform: " xstr(PLATFORM) " $";

extern "C" {

const char*
CondorVersion( void )
{
	return CondorVersionString;
}

const char*
CondorPlatform( void )
{
	return CondorPlatformString;
}

} /* extern "C" */

<|endoftext|>


<commit_before><commit_msg>FEM: add basic support of Nastran-95<commit_after><|endoftext|>