Alteracao na mutacao

Alteracao na mutacao

#define DATABASE(x,y) dataBase[x*NUM_VARIAVEIS + y]

#include "representacao.h"
#include "substituicao.cl"
#include "utils.cl"
#include "parser.cl"
#include "gramatica.cl"
#include "avaliacao.cl"

int torneio(__global individuo *populacao, int indice_participante, cburng4x32 *rng) {

    int vencedor = indice_participante % TAMANHO_POPULACAO;
    int i=0; int aleatorio = 0;

    while(i < TAMANHO_TORNEIO) {

 	aleatorio = rand(rng) % (TAMANHO_POPULACAO);

        if(populacao[aleatorio].aptidao > populacao[vencedor].aptidao){
            vencedor = aleatorio;
        }

        i++;
    }

    return vencedor;
}

void crossover_um_ponto(individuo *pais, individuo *filhos, cburng4x32 *rng){

   int i;

    //Gera número entre 0 e TAMANHO_INDIVIDUO-1
    int ponto = rand(rng) % (TAMANHO_INDIVIDUO);

    for(i=0;i<=ponto;i++){
       filhos[0].genotipo[i] = pais[0].genotipo[i];
       filhos[1].genotipo[i] = pais[1].genotipo[i];
    }

    for(i=ponto;i<TAMANHO_INDIVIDUO;i++){
       filhos[0].genotipo[i] = pais[1].genotipo[i];
       filhos[1].genotipo[i] = pais[0].genotipo[i];
   }
}

void crossover_um_ponto2(__local individuo *pais, __local individuo *filhos, cburng4x32 *rng, int lid, int ponto){

    int i;

    for(i=0;i<=ponto;i++){
       //filhos[0].genotipo[i] = pais[0].genotipo[i];
       //filhos[1].genotipo[i] = pais[1].genotipo[i];

       filhos[lid].genotipo[i] = pais[lid].genotipo[i];
    }

    for(i=ponto;i<TAMANHO_INDIVIDUO;i++){
       //filhos[0].genotipo[i] = pais[1].genotipo[i];
       //filhos[1].genotipo[i] = pais[0].genotipo[i];

       filhos[lid].genotipo[i] = pais[1-lid].genotipo[i];
   }
}

void crossover_um_ponto3(__local individuo *pais, individuo *filhos, cburng4x32 *rng, int lid, int ponto){

    int i, indice1, indice2;

    if(lid % 2 ==0){
	indice1 = lid;
        indice2 = indice1+1;
    }
    else{
	indice1 = lid;
        indice2 = indice1-1;
    }

    for(i=0;i<=ponto; i++){
       filhos[0].genotipo[i] = pais[indice1].genotipo[i];
    }

    for(i=ponto;i<TAMANHO_INDIVIDUO;i++){
       filhos[0].genotipo[i] = pais[indice2].genotipo[i];
   }
}

void crossover_um_ponto4(individuo *pais, individuo *filhos, cburng4x32 *rng){

    int i;

    //Gera número entre 0 e TAMANHO_INDIVIDUO-1
    int ponto = rand(rng) % (TAMANHO_INDIVIDUO);

    for(i=0;i<=ponto;i++){
       filhos[0].genotipo[i] = pais[0].genotipo[i];
    }

    for(i=ponto;i<TAMANHO_INDIVIDUO;i++){
       filhos[0].genotipo[i] = pais[1].genotipo[i];
    }
}

void recombinacao(individuo *pais, individuo *filhos, float chance, cburng4x32 *rng){

    //Gera um número entre 0 e 1
    float aleatorio = u_rand(rng);

    if (aleatorio<chance) {
        crossover_um_ponto(pais, filhos, rng);
    }
    else{
       filhos[0] = pais[0];
       filhos[1] = pais[1];
    }
}

void recombinacao2(__local individuo *pais,
		   __local individuo *filhos,
 		   __local int * recombinar, cburng4x32 *rng,
		   int lid,
		   __local int *pontoCrossOver){

    if (recombinar==1) {
        crossover_um_ponto2(pais, filhos, rng, lid, pontoCrossOver);
    }
    else{
       filhos[lid] = pais[lid];
       //filhos[1-lid] = pais[1-lid];
    }
}

void recombinacao3(__local individuo *pais,
		   individuo *filhos,
 		   __local int * recombinar,
		   cburng4x32 *rng,
		   int lid,
		   __local int *pontosCrossOver){

    if (recombinar==1) {
        crossover_um_ponto3(pais, filhos, rng, lid, pontosCrossOver);
    }
    else{
       filhos[0] = pais[lid];
    }
}

void recombinacao4(individuo *pais, individuo *filhos, float chance, cburng4x32 *rng){

    //Gera um número entre 0 e 1
    float aleatorio = u_rand(rng);

    if (aleatorio<=chance) {
       crossover_um_ponto4(pais, filhos, rng);
    }
    else{
       filhos[0] = pais[0];
    }
}

void mutacao(individuo *p, float chance, cburng4x32 *rng){

    int mutacoes = (int)(TAMANHO_INDIVIDUO * chance);
    int aleatorio=0;

    for(int i=0;i<mutacoes;i++) {

        aleatorio = rand(rng) % TAMANHO_INDIVIDUO;

        if(p->genotipo[aleatorio])
            p->genotipo[aleatorio] = 0;
        else p->genotipo[aleatorio] = 1;
    }
}

void mutacao2(__local individuo *p, float chance, cburng4x32 *rng){

    int mutacoes = (int)(TAMANHO_INDIVIDUO * chance);
    int aleatorio=0;

    for(int i=0;i<mutacoes;i++) {

        aleatorio = rand(rng) % TAMANHO_INDIVIDUO;

        if(p->genotipo[aleatorio])
            p->genotipo[aleatorio] = 0;
        else p->genotipo[aleatorio] = 1;
    }
}

__kernel void inicializa_populacao(__global individuo *pop, const int seed){

    int tid = get_global_id(0),
        lid = get_local_id(0);

    int lseed = seed+tid;

    //Inicializa RNG
    cburng4x32 rng;
    cburng4x32_init(&rng);
    rng.key.v[0] = lseed;
    rng.ctr.v[0] = 0;
    rng.ctr.v[1] = 0;

    for(int j=0; j < TAMANHO_INDIVIDUO; j++){
        pop[tid].genotipo[j] = rand(&rng) % 2;
    }
}

/*
 KERNEL 0:
 Utiliza TAMANHO_POPULACAO/2 itens de trabalho, cada 1 responsável por selecionar 2 pais
 e gerar 2 filhos, realizando crossover e mutação.
*/
__kernel void iteracao_2_por_work_item(__global individuo *pop,
			const int geracao,
			const int fixed_seed,
			__global individuo *newPop,
			__global struct r123array4x32 *counter)
{

    int tid  = get_global_id(0)*2,
        lid  = get_local_id(0),
	seed = fixed_seed + tid;

    //Inicializa RNG
    cburng4x32 rng;
    cburng4x32_init(&rng);
    rng.key.v[0] = seed;

    if(geracao <= 1){
    	 rng.ctr.v[0] = rng.ctr.v[1] = 0;
    }
    else{
    	rng.ctr = counter[tid];
    }

    /*
	Seleção
    */

    individuo pais[2], filhos[2];

    pais[0] = pop[torneio(pop, tid, &rng)];
    pais[1] = pop[torneio(pop, tid+1, &rng)];

    /*
	Recombinação
    */

    recombinacao(pais, filhos, (float)TAXA_DE_RECOMBINACAO, &rng);

    /*
	Mutação
    */

    mutacao(&filhos[0], TAXA_DE_MUTACAO, &rng);
    mutacao(&filhos[1], TAXA_DE_MUTACAO, &rng);

    /*
       Avaliação
    */

    //__private short fenotipo[DIMENSOES_PROBLEMA];

    //filhos[0].aptidao = funcao_de_avaliacao(filhos[0], fenotipo);
    //filhos[1].aptidao = funcao_de_avaliacao(filhos[1], fenotipo);

    newPop[tid]   = filhos[0];
    newPop[tid+1] = filhos[1];

    counter[tid] = rng.ctr;
}

/*
  KERNEL 1:

 Utiliza TAMANHO_POPULACAO itens de trabalho, e 2 itens por unidade de computação. O item de trabalho 0 é responsável por
 selecionar os 2 pais; logo em seguida há um sincronismo, para que o item 1 tenha acesso (via memória local) aos indivíduos selecionados.
 Em seguida cada item realiza sua parte do crossover e a mutação do indivíduo resultante.

*/
__kernel void iteracao_2_por_work_group(__global individuo *pop,
			const int geracao,
			int fixed_seed,
			__global individuo *newPop,
			__global struct r123array4x32 *counter)
{

    int tid  = get_global_id(0),
        lid  = get_local_id(0),
	seed = fixed_seed + tid;

    //Inicializa RNG
    cburng4x32 rng;
    cburng4x32_init(&rng);
    rng.key.v[0] = seed;

    if(geracao <= 1){
    	 rng.ctr.v[0] = rng.ctr.v[1] = 0;
    }
    else{
    	rng.ctr = counter[tid];
    }

    /*
	Seleção
    */
    __local individuo pais[2], filhos[2];
    __local int recombinar, pontoCrossOver;

    if(lid == 0){

    	pais[0] = pop[torneio(pop, tid, &rng)];
    	pais[1] = pop[torneio(pop, tid+1, &rng)];

	float aleatorio = u_rand(&rng);

        pontoCrossOver = rand(&rng)  % (TAMANHO_INDIVIDUO);

	recombinar = aleatorio < TAXA_DE_RECOMBINACAO;
    }

    barrier(CLK_LOCAL_MEM_FENCE);

    /*
        Recombinação
    */

    recombinacao2(pais, filhos, recombinar, &rng, lid, pontoCrossOver);

    /*
	    Mutação
    */

    mutacao2(&filhos[lid], TAXA_DE_MUTACAO, &rng);

    /*
       Avaliação
    */

    /*__private short fenotipo[DIMENSOES_PROBLEMA];
    filhos[lid].aptidao = funcao_de_avaliacao(filhos[lid], fenotipo);*/

    newPop[tid]  = filhos[lid];
    counter[tid] = rng.ctr;
}

/*
  KERNEL 2**:

 Semelhante ao KERNEL 1, porém utilizando N itens de trabalho por unidade de computação.
 Neste caso, os itens de trabalho pares (tid % 2 == 0) realizam a seleção dos 2 pais, e também
 a decisão da ocorrência do crossover. É feito então um sincronismo para que todos os itens tenham acesso (via memória local)
 aos indivíduos selecionados.
*/

__kernel void iteracao_n_por_work_group(__global individuo *pop,
			const int geracao,
			int fixed_seed,
			__global individuo *newPop,
			__global struct r123array4x32 *counter,
			__local individuo *pais,
			__local int *recombinar,
			__local int *pontosCrossover)
{

    int tid  = get_global_id(0),
        lid  = get_local_id(0),
	seed = fixed_seed + tid;

    if(tid >= TAMANHO_POPULACAO) return;

    //Inicializa RNG
    cburng4x32 rng;
    cburng4x32_init(&rng);
    rng.key.v[0] = seed;

    if(geracao <= 1){
    	 rng.ctr.v[0] = rng.ctr.v[1] = 0;
    }
    else{
    	rng.ctr = counter[tid];
    }

    /*
	Seleção
    */

    int index = (int)lid/2;

    if(lid % 2 == 0){

    	pais[lid]    = pop[torneio(pop, tid, &rng)];
    	pais[lid+1]  = pop[torneio(pop, tid+1, &rng)];

	/*
           Recombinação
        */

	float aleatorio = u_rand(&rng);

        pontosCrossover[index] = rand(&rng)  % (TAMANHO_INDIVIDUO);

	recombinar[index] = aleatorio < TAXA_DE_RECOMBINACAO;
    }

    barrier(CLK_LOCAL_MEM_FENCE);

    individuo filhos[1];

    recombinacao3(pais, filhos, recombinar[index], &rng, lid, pontosCrossover[index]);

    /*
	Mutação
    */

    mutacao(&filhos[0], TAXA_DE_MUTACAO, &rng);

    /*
       Avaliação
    */

    //short fenotipo[DIMENSOES_PROBLEMA];
    //filhos[0].aptidao = funcao_de_avaliacao(filhos[0], fenotipo);

    newPop[tid] = filhos[0];

    counter[tid] = rng.ctr;
}

#define DATABASE(x,y) dataBase[x*NUM_VARIAVEIS + y]

#include "representacao.h"
#include "substituicao.cl"
#include "utils.cl"
#include "parser.cl"
#include "gramatica.cl"
#include "avaliacao.cl"

int torneio(__global individuo *populacao, int indice_participante, cburng4x32 *rng) {

    int vencedor = indice_participante % TAMANHO_POPULACAO;
    int i=0; int aleatorio = 0;

    while(i < TAMANHO_TORNEIO) {

 	aleatorio = rand(rng) % (TAMANHO_POPULACAO);

        if(populacao[aleatorio].aptidao > populacao[vencedor].aptidao){
            vencedor = aleatorio;
        }

        i++;
    }

    return vencedor;
}

void crossover_um_ponto(individuo *pais, individuo *filhos, cburng4x32 *rng){

   int i;

    //Gera número entre 0 e TAMANHO_INDIVIDUO-1
    int ponto = rand(rng) % (TAMANHO_INDIVIDUO);

    for(i=0;i<=ponto;i++){
       filhos[0].genotipo[i] = pais[0].genotipo[i];
       filhos[1].genotipo[i] = pais[1].genotipo[i];
    }

    for(i=ponto;i<TAMANHO_INDIVIDUO;i++){
       filhos[0].genotipo[i] = pais[1].genotipo[i];
       filhos[1].genotipo[i] = pais[0].genotipo[i];
   }
}

void crossover_um_ponto2(__local individuo *pais, __local individuo *filhos, cburng4x32 *rng, int lid, int ponto){

    int i;

    for(i=0;i<=ponto;i++){
       //filhos[0].genotipo[i] = pais[0].genotipo[i];
       //filhos[1].genotipo[i] = pais[1].genotipo[i];

       filhos[lid].genotipo[i] = pais[lid].genotipo[i];
    }

    for(i=ponto;i<TAMANHO_INDIVIDUO;i++){
       //filhos[0].genotipo[i] = pais[1].genotipo[i];
       //filhos[1].genotipo[i] = pais[0].genotipo[i];

       filhos[lid].genotipo[i] = pais[1-lid].genotipo[i];
   }
}

void crossover_um_ponto3(__local individuo *pais, individuo *filhos, cburng4x32 *rng, int lid, int ponto){

    int i, indice1, indice2;

    if(lid % 2 ==0){
	indice1 = lid;
        indice2 = indice1+1;
    }
    else{
	indice1 = lid;
        indice2 = indice1-1;
    }

    for(i=0;i<=ponto; i++){
       filhos[0].genotipo[i] = pais[indice1].genotipo[i];
    }

    for(i=ponto;i<TAMANHO_INDIVIDUO;i++){
       filhos[0].genotipo[i] = pais[indice2].genotipo[i];
   }
}

void crossover_um_ponto4(individuo *pais, individuo *filhos, cburng4x32 *rng){

   int i;

    //Gera número entre 0 e TAMANHO_INDIVIDUO-1
    int ponto = rand(rng) % (TAMANHO_INDIVIDUO);

    for(i=0;i<=ponto;i++){
       filhos[0].genotipo[i] = pais[0].genotipo[i];
    }

    for(i=ponto;i<TAMANHO_INDIVIDUO;i++){
       filhos[0].genotipo[i] = pais[1].genotipo[i];
   }
}

void recombinacao(individuo *pais, individuo *filhos, float chance, cburng4x32 *rng){

    //Gera um número entre 0 e 1
    float aleatorio = u_rand(rng);

    if (aleatorio<chance) {
        crossover_um_ponto(pais, filhos, rng);
    }
    else{
       filhos[0] = pais[0];
       filhos[1] = pais[1];
    }
}

void recombinacao2(__local individuo *pais,
		   __local individuo *filhos,
 		   __local int * recombinar, cburng4x32 *rng,
		   int lid,
		   __local int *pontoCrossOver){

    if (recombinar==1) {
        crossover_um_ponto2(pais, filhos, rng, lid, pontoCrossOver);
    }
    else{
       filhos[lid] = pais[lid];
       //filhos[1-lid] = pais[1-lid];
    }
}

void recombinacao3(__local individuo *pais,
		   individuo *filhos,
 		   __local int * recombinar,
		   cburng4x32 *rng,
		   int lid,
		   __local int *pontosCrossOver){

    if (recombinar==1) {
        crossover_um_ponto3(pais, filhos, rng, lid, pontosCrossOver);
    }
    else{
       filhos[0] = pais[lid];
    }
}

void recombinacao4(individuo *pais, individuo *filhos, float chance, cburng4x32 *rng){

    //Gera um número entre 0 e 1
    float aleatorio = u_rand(rng);

    if (aleatorio<=chance) {
       crossover_um_ponto4(pais, filhos, rng);
    }
    else{
       filhos[0] = pais[0];
    }
}

void mutacao(individuo *p, float chance, cburng4x32 *rng){

    for(int i=0;i<TAMANHO_INDIVIDUO;i++) {

        //gera um número entre 0 e 1
        float aleatorio = u_rand(rng);

        if (aleatorio<=chance) {
           p->genotipo[i] = (p->genotipo[i]+1) % 2;
        }
    }
}

void mutacao2(__local individuo *p, float chance, cburng4x32 *rng){

    for(int i=0;i<TAMANHO_INDIVIDUO;i++) {

        //gera um número entre 0 e 1
        float aleatorio = u_rand(rng);

        if (aleatorio<chance) {
           p->genotipo[i] = (p->genotipo[i]+1) % 2;
        }
    }
}

__kernel void inicializa_populacao(__global individuo *pop, const int seed){

    int tid = get_global_id(0),
        lid = get_local_id(0);

    int lseed = seed+tid;

    //Inicializa RNG
    cburng4x32 rng;
    cburng4x32_init(&rng);
    rng.key.v[0] = lseed;
    rng.ctr.v[0] = 0;
    rng.ctr.v[1] = 0;

    for(int j=0; j < TAMANHO_INDIVIDUO; j++){
        pop[tid].genotipo[j] = rand(&rng) % 2;
    }
}

/*
 KERNEL 0:
 Utiliza TAMANHO_POPULACAO/2 itens de trabalho, cada 1 responsável por selecionar 2 pais
 e gerar 2 filhos, realizando crossover e mutação.
*/
__kernel void iteracao_2_por_work_item(__global individuo *pop,
			const int geracao,
			const int fixed_seed,
			__global individuo *newPop,
			__global struct r123array4x32 *counter)
{

    int tid  = get_global_id(0)*2,
        lid  = get_local_id(0),
	seed = fixed_seed + tid;

    //Inicializa RNG
    cburng4x32 rng;
    cburng4x32_init(&rng);
    rng.key.v[0] = seed;

    if(geracao <= 1){
    	 rng.ctr.v[0] = rng.ctr.v[1] = 0;
    }
    else{
    	rng.ctr = counter[tid];
    }

    /*
	Seleção
    */

    individuo pais[2], filhos[2];

    pais[0] = pop[torneio(pop, tid, &rng)];
    pais[1] = pop[torneio(pop, tid+1, &rng)];

    /*
	Recombinação
    */

    recombinacao(pais, filhos, (float)TAXA_DE_RECOMBINACAO, &rng);

    /*
	Mutação
    */

    mutacao(&filhos[0], TAXA_DE_MUTACAO, &rng);
    mutacao(&filhos[1], TAXA_DE_MUTACAO, &rng);

    /*
       Avaliação
    */

    //__private short fenotipo[DIMENSOES_PROBLEMA];

    //filhos[0].aptidao = funcao_de_avaliacao(filhos[0], fenotipo);
    //filhos[1].aptidao = funcao_de_avaliacao(filhos[1], fenotipo);

    newPop[tid]   = filhos[0];
    newPop[tid+1] = filhos[1];

    counter[tid] = rng.ctr;
}

/*
  KERNEL 1:

 Utiliza TAMANHO_POPULACAO itens de trabalho, e 2 itens por unidade de computação. O item de trabalho 0 é responsável por
 selecionar os 2 pais; logo em seguida há um sincronismo, para que o item 1 tenha acesso (via memória local) aos indivíduos selecionados.
 Em seguida cada item realiza sua parte do crossover e a mutação do indivíduo resultante.

*/
__kernel void iteracao_2_por_work_group(__global individuo *pop,
			const int geracao,
			int fixed_seed,
			__global individuo *newPop,
			__global struct r123array4x32 *counter)
{

    int tid  = get_global_id(0),
        lid  = get_local_id(0),
	seed = fixed_seed + tid;

    //Inicializa RNG
    cburng4x32 rng;
    cburng4x32_init(&rng);
    rng.key.v[0] = seed;

    if(geracao <= 1){
    	 rng.ctr.v[0] = rng.ctr.v[1] = 0;
    }
    else{
    	rng.ctr = counter[tid];
    }

    /*
	Seleção
    */
    __local individuo pais[2], filhos[2];
    __local int recombinar, pontoCrossOver;

    if(lid == 0){

    	pais[0] = pop[torneio(pop, tid, &rng)];
    	pais[1] = pop[torneio(pop, tid+1, &rng)];

	float aleatorio = u_rand(&rng);

        pontoCrossOver = rand(&rng)  % (TAMANHO_INDIVIDUO);

	recombinar = aleatorio < TAXA_DE_RECOMBINACAO;
    }

    barrier(CLK_LOCAL_MEM_FENCE);

    /*
        Recombinação
    */

    recombinacao2(pais, filhos, recombinar, &rng, lid, pontoCrossOver);

    /*
	Mutação
    */

    mutacao2(&filhos[lid], TAXA_DE_MUTACAO, &rng);

    /*
       Avaliação
    */

    /*__private short fenotipo[DIMENSOES_PROBLEMA];
    filhos[lid].aptidao = funcao_de_avaliacao(filhos[lid], fenotipo);*/

    newPop[tid]  = filhos[lid];

    counter[tid] = rng.ctr;
}

/*
  KERNEL 2**:

 Semelhante ao KERNEL 1, porém utilizando N itens de trabalho por unidade de computação.
 Neste caso, os itens de trabalho pares (tid % 2 == 0) realizam a seleção dos 2 pais, e também
 a decisão da ocorrência do crossover. É feito então um sincronismo para que todos os itens tenham acesso (via memória local)
 aos indivíduos selecionados.
*/

__kernel void iteracao_n_por_work_group(__global individuo *pop,
			const int geracao,
			int fixed_seed,
			__global individuo *newPop,
			__global struct r123array4x32 *counter,
			__local individuo *pais,
			__local int *recombinar,
			__local int *pontosCrossover)
{

    int tid  = get_global_id(0),
        lid  = get_local_id(0),
	seed = fixed_seed + tid;

    if(tid >= TAMANHO_POPULACAO) return;

    //Inicializa RNG
    cburng4x32 rng;
    cburng4x32_init(&rng);
    rng.key.v[0] = seed;

    if(geracao <= 1){
    	 rng.ctr.v[0] = rng.ctr.v[1] = 0;
    }
    else{
    	rng.ctr = counter[tid];
    }

    /*
	Seleção
    */

    int index = (int)lid/2;

    if(lid % 2 == 0){

    	pais[lid]    = pop[torneio(pop, tid, &rng)];
    	pais[lid+1]  = pop[torneio(pop, tid+1, &rng)];

	/*
           Recombinação
        */

	float aleatorio = u_rand(&rng);

        pontosCrossover[index] = rand(&rng)  % (TAMANHO_INDIVIDUO);

	recombinar[index] = aleatorio < TAXA_DE_RECOMBINACAO;
    }

    barrier(CLK_LOCAL_MEM_FENCE);

    individuo filhos[1];

    recombinacao3(pais, filhos, recombinar[index], &rng, lid, pontosCrossover[index]);

    /*
	Mutação
    */

    mutacao(&filhos[0], TAXA_DE_MUTACAO, &rng);

    /*
       Avaliação
    */

    //short fenotipo[DIMENSOES_PROBLEMA];
    //filhos[0].aptidao = funcao_de_avaliacao(filhos[0], fenotipo);

    newPop[tid] = filhos[0];

    counter[tid] = rng.ctr;
}


staticed const the phong inside kernel.cl

#include "kernel_header.h"
#include "kernel_matrix.h"
#include "kernel_cam.h"
#include "kernel_color.h"
#include "kernel_cone.h"
#include "kernel_cylinder.h"
#include "kernel_data.h"
#include "kernel_debug.h"
#include "kernel_plane.h"
#include "kernel_sphere.h"

float3					rotate_obj(float3 v, float pitch, float yaw, float roll)
{
	float3				res;

	res = rotat_zyx(v, pitch, yaw, roll);

	return (normalize(res));
}

static t_hit			ray_hit(const float3 origin, const float3 ray, const t_scene scene)
{
	unsigned int			i = 0;
	int						max = get_max_obj(PARAM);
	t_hit					hit = hit_init();
	float					dist = 0;

	while (i < max)
	{
		if (i < PARAM->n_cones)
			if (((dist = inter_cone(scene, i, ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
			{
				hit.dist = dist;
				hit.type = 1;
				hit.id = i;
			}
		if (i < PARAM->n_cylinders)
			if (((dist = inter_cylinder(CYLIND[i].height, rotate_obj(CYLIND[i].dir, CYLIND[i].pitch, CYLIND[i].yaw, 0), CYLIND[i].radius, CYLIND[i].pos, ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
			{
				hit.dist = dist;
				hit.type = 2;
				hit.id = i;
			}
		if (i < PARAM->n_planes)
			if (((dist = inter_plan(scene, i, ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
			{
				hit.dist = dist;
				hit.type = 4;
				hit.id = i;
			}
		if (i < PARAM->n_spheres)
			if (((dist = inter_sphere(scene, i, ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
			{
				hit.dist = dist;
				hit.type = 5;
				hit.id = i;
			}
		i++;
	}
	return (hit);
}

float3			rotate_matrix(float angle, float3 v)
{
	float3		res;

	res.x = v.x;
	res.y = (cos(angle) * v.y) - (sin(angle) * v.z);
	res.z = (sin(angle) * v.y) + (cos(angle) * v.z);
	return (res);
}

float16			trans_matrix(float3 dir, float angle)
{
	float16		res = 0;
	float3		rot = 0;

	rot = rotate_obj(dir, 0, angle, 0);
	res[0] = rot.x;
	res[1] = rot.y;
	res[2] = rot.z;
	rot = rotate_obj(dir, -angle, 0, 0);
	res[4] = rot.x;
	res[5] = rot.y;
	res[6] = rot.z;
	res[8] = dir.x;
	res[9] = dir.y;
	res[10] = dir.z;
	return (res);
}

float3			apply_matrix(float16 mat, float3 v)
{
	float3		res = 0;

	res.x = mat[0] * v.x + mat[4] * v.y + mat[8] * v.z;
	res.y = mat[1] * v.x + mat[5] * v.y + mat[9] * v.z;
	res.z = mat[2] * v.x + mat[6] * v.y + mat[10] * v.z;
	return (res);
}

float3			get_hit_normale(t_scene scene, t_hit hit)
{
	float3		res;

	if (hit.type == 1)
	{
		float k = CONES[hit.id].angle * DEG2RAD;
		k = tan(k);
		k = 1 + k * k;
		res = dot(-scene.ray, normalize(CONES[hit.id].dir)) * hit.dist - dot(ACTIVECAM.pos + PARAM->mvt - CONES[hit.id].pos, normalize(CONES[hit.id].dir));
		res = ((hit.pos - normalize(CONES[hit.id].pos)) - (k * normalize(CONES[hit.id].dir) * res)) * -1;
	}
	else if (hit.type == 2)
	{
		/*float3	base = CYLIND[hit.id].pos;
		res = hit.pos;

		res = rotate_matrix(45 * DEG2RAD, res);
		base.z = res.z;
		base = rotate_matrix(-45 * DEG2RAD, base);
		res = rotate_matrix(-45 * DEG2RAD, res);
		res -= base;*/
//		res = dot(-scene.ray, normalize(CYLIND[hit.id].dir) * hit.dist + \
//			dot(ACTIVECAM.pos + PARAM->mvt - CYLIND[hit.id].pos, normalize(CYLIND[hit.id].dir)));
//		res = hit.pos - CYLIND[hit.id].pos - normalize(CYLIND[hit.id].dir) * res;

	/*	res = normalize(hit.pos - CYLIND[hit.id].pos);
	// fonctionne pour cylindre aligné en Z
		if (dot(normalize(CYLIND[hit.id].dir), res) < 0)
		{
			res += normalize(CYLIND[hit.id].dir);
			res.z += 1;
		}
		else
		{
			res -= normalize(CYLIND[hit.id].dir);
			res.z += 1;
		}*/
		int		i = hit.id;
		float3	dir = rotate_obj(CYLIND[i].dir, CYLIND[i].pitch, CYLIND[i].yaw, 0);
		float16 ok = trans_matrix(dir, 90);
		//printf("the first\n0 : %f, 1 : %f, 2 : %f\n4 : %f, 5 : %f, 6 : %f\n8 : %f, 9 : %f, 10 : %f\n\n", ok[0], ok[1], ok[2], ok[4], ok[5], ok[6], ok[8], ok[9], ok[10]);
		res = apply_matrix(ok, hit.pos) - CYLIND[i].pos;
		res.z = 0;
		//ok = trans_matrix(dir, -90);
		//printf("the second\n0 : %f, 1 : %f, 2 : %f\n4 : %f, 5 : %f, 6 : %f\n8 : %f, 9 : %f, 10 : %f\n\n", ok[0], ok[1], ok[2], ok[4], ok[5], ok[6], ok[8], ok[9], ok[10]);
		res = apply_matrix(-ok, res);
		/*res = trans_matrix(dir, hit.pos);
		res = res - CYLIND[i].pos;
		res.z = 0;*/
		//res = trans_matrix(dir, res;
		/*
		nbase.dist = inter_cylinder(CYLIND[i].height, CYLIND[i].dir, CYLIND[i].radius, CYLIND[i].pos,  rotate_obj(scene.ray, -CYLIND[i].pitch, CYLIND[i].yaw, 0), (ACTIVECAM.pos + PARAM->mvt));
		nbase.pos = (ACTIVECAM.pos + PARAM->mvt) + normalize((rotate_obj(scene.ray, -CYLIND[i].pitch, -CYLIND[i].yaw, 0)) * nbase.dist);
		res = nbase.pos - CYLIND[i].pos;
		res.z = 0;
		res = rotate_obj(normalize(res), CYLIND[i].pitch, CYLIND[i].yaw, 0);*/
	}
	else if (hit.type == 4)
	{
		if (dot(PLANE[hit.id].normale, -scene.ray) < 0)
			res = -PLANE[hit.id].normale;
		else
			res = PLANE[hit.id].normale;
	}
	else if (hit.type == 5)
		res = hit.pos - SPHERE[hit.id].pos;
	return (normalize(res));
}

static unsigned int			phong(const t_hit hit, const t_scene scene)
{
	int					i = -1;
	unsigned int		res_color = get_ambient(scene, get_obj_hue(scene, hit));
	float				tmp;
	float3				reflect = 0;

	t_light_ray			light_ray;
	t_hit				light_hit = hit_init();

	while (++i < PARAM->n_lights)
	{
		tmp = 0;
		light_ray.dir = LIGHT[i].pos - hit.pos;
		light_ray.dist = length(light_ray.dir);
		light_ray.dir = normalize(light_ray.dir);
		light_hit = ray_hit(hit.pos, light_ray.dir, scene);
		light_hit.id = i;
		light_hit.type = 3;
		if (light_hit.dist < light_ray.dist && light_hit.dist > 0)
		;
		else
		{
			tmp = dot(hit.normale, light_ray.dir);
			if (tmp > 0)
				res_color = color_diffuse(scene, hit, light_hit, res_color, tmp);
			reflect = normalize(((float)(2.0 * dot(hit.normale, light_ray.dir)) * hit.normale) - light_ray.dir);
			tmp = dot(reflect, -scene.ray);
			if (tmp > 0)
				res_color = color_specular(scene, hit, light_hit, res_color, tmp);
		}
	}
	return (res_color);
}

unsigned int			phong2(t_hit hit, t_scene scene)
{
	int					i = -1;
	unsigned int		res_color = get_ambient(scene, get_obj_hue(scene, hit));
	float				tmp = 0;
	float3				reflect = 0;

	t_light_ray			light_ray;
	t_hit				light_hit;

	while (++i < PARAM->n_lights)
	{
		light_ray.dir = LIGHT[i].pos - hit.pos;
		light_ray.dist = length(light_ray.dir);
		light_ray.dir = normalize(light_ray.dir);
		light_hit = ray_hit(hit.pos, light_ray.dir, scene);
		if (light_hit.dist < light_ray.dist && light_hit.dist > 0)
		;
		else
		{
			tmp = dot(hit.normale, light_ray.dir);
			if (tmp > 0)
				res_color = color_diffuse(scene, hit, light_hit, res_color, tmp);
			reflect = normalize(((float)(2.0 * dot(hit.normale, light_ray.dir)) * hit.normale) - light_ray.dir);
			tmp = dot(reflect, -scene.ray);
			if (tmp > 0)
				res_color = color_specular(scene, hit, light_hit, res_color, tmp);
		}
	}
	return (res_color);
}

static unsigned int		bounce(const t_scene scene, const t_hit old_hit, const int depth)
{
	int				i = depth;
	unsigned int	color = 0;
	float3			reflex = 0;
	t_hit			new_hit;
	while (i > 0)
	{
		reflex = normalize(scene.ray - (2 * (float)dot(old_hit.normale, scene.ray) * old_hit.normale));
		new_hit.dist = MAX_DIST;
		new_hit = ray_hit(old_hit.pos, reflex, scene);
		if (new_hit.dist > 0 && new_hit.dist < MAX_DIST)
		{
			new_hit.pos = (new_hit.dist * reflex) + old_hit.pos;
			new_hit.normale = get_hit_normale(scene, new_hit);
			new_hit.pos = new_hit.pos + ((new_hit.dist / 100) * new_hit.normale);
			color += 0.1 * phong2(new_hit, scene);
		}
		i--;
	}
	return (color);
}

static unsigned int	get_pixel_color(const t_scene scene)
{
	t_hit			hit;
	int				depth = PARAM->depth;
	unsigned int	color  = 0;
	unsigned int	bounce_color = 0;

	hit.dist = MAX_DIST;
	hit = ray_hit((ACTIVECAM.pos + PARAM->mvt), scene.ray, scene);
	if (hit.dist > 0 && hit.dist < MAX_DIST) // ajout d'une distance max pour virer acnee mais pas fiable a 100%
	{
		hit.pos = (hit.dist * scene.ray) + (ACTIVECAM.pos + PARAM->mvt);
		hit.normale = get_hit_normale(scene, hit);
		hit.pos = hit.pos + ((hit.dist / 100) * hit.normale);
		color = phong(hit, scene);
		if (depth > 0)
			bounce_color = bounce(scene, hit, depth);
		return (color + bounce_color);
//		return (blend_add(color, 0.8*bounce_color));
	}
	return (get_ambient(scene, BACKCOLOR));
}

__kernel void	ray_trace(__global		char		*output,
						  				t_param		param,
						  __constant	t_cam		*cameras,
						  __constant	t_cone		*cones,
						  __constant	t_cylinder	*cylinders,
						  __constant	t_light		*lights,
						  __constant	t_plane		*planes,
						  __constant	t_sphere	*spheres,
						  __global		t_hit		*target_obj)
{
	t_scene		scene = grab_data(cameras, cones, cylinders, lights, planes, spheres, param);
	scene.pix.x = get_global_id(0);
	scene.pix.y = get_global_id(1);
	int			id = scene.pix.x + (PARAM->win_w * scene.pix.y); // NE PAS VIRER ID CAR BESOIN DANS MACRO OUTPUTE
	scene.ray = get_ray_cam(ACTIVECAM, scene, scene.pix.x ,scene.pix.y);
	if (scene.pix.x == PARAM->mou_x && scene.pix.y == PARAM->mou_y)
		*target_obj = ray_hit((ACTIVECAM.pos + PARAM->mvt), scene.ray, scene);
	OUTPUTE = get_pixel_color(scene);
}

#include "kernel_header.h"
#include "kernel_matrix.h"
#include "kernel_cam.h"
#include "kernel_color.h"
#include "kernel_cone.h"
#include "kernel_cylinder.h"
#include "kernel_data.h"
#include "kernel_debug.h"
#include "kernel_plane.h"
#include "kernel_sphere.h"

float3					rotate_obj(float3 v, float pitch, float yaw, float roll)
{
	float3				res;

	res = rotat_zyx(v, pitch, yaw, roll);

	return (normalize(res));
}

static t_hit			ray_hit(const float3 origin, const float3 ray, const t_scene scene)
{
	unsigned int			i = 0;
	int						max = get_max_obj(PARAM);
	t_hit					hit = hit_init();
	float					dist = 0;

	while (i < max)
	{
		if (i < PARAM->n_cones)
			if (((dist = inter_cone(scene, i, ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
			{
				hit.dist = dist;
				hit.type = 1;
				hit.id = i;
			}
		if (i < PARAM->n_cylinders)
			if (((dist = inter_cylinder(CYLIND[i].height, rotate_obj(CYLIND[i].dir, CYLIND[i].pitch, CYLIND[i].yaw, 0), CYLIND[i].radius, CYLIND[i].pos, ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
			{
				hit.dist = dist;
				hit.type = 2;
				hit.id = i;
			}
		if (i < PARAM->n_planes)
			if (((dist = inter_plan(scene, i, ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
			{
				hit.dist = dist;
				hit.type = 4;
				hit.id = i;
			}
		if (i < PARAM->n_spheres)
			if (((dist = inter_sphere(scene, i, ray, origin)) < hit.dist || hit.dist == 0) && dist > 0)
			{
				hit.dist = dist;
				hit.type = 5;
				hit.id = i;
			}
		i++;
	}
	return (hit);
}

float3			rotate_matrix(float angle, float3 v)
{
	float3		res;

	res.x = v.x;
	res.y = (cos(angle) * v.y) - (sin(angle) * v.z);
	res.z = (sin(angle) * v.y) + (cos(angle) * v.z);
	return (res);
}

float16			trans_matrix(float3 dir, float angle)
{
	float16		res = 0;
	float3		rot = 0;

	rot = rotate_obj(dir, 0, angle, 0);
	res[0] = rot.x;
	res[1] = rot.y;
	res[2] = rot.z;
	rot = rotate_obj(dir, -angle, 0, 0);
	res[4] = rot.x;
	res[5] = rot.y;
	res[6] = rot.z;
	res[8] = dir.x;
	res[9] = dir.y;
	res[10] = dir.z;
	return (res);
}

float3			apply_matrix(float16 mat, float3 v)
{
	float3		res = 0;

	res.x = mat[0] * v.x + mat[4] * v.y + mat[8] * v.z;
	res.y = mat[1] * v.x + mat[5] * v.y + mat[9] * v.z;
	res.z = mat[2] * v.x + mat[6] * v.y + mat[10] * v.z;
	return (res);
}

float3			get_hit_normale(t_scene scene, t_hit hit)
{
	float3		res;

	if (hit.type == 1)
	{
		float k = CONES[hit.id].angle * DEG2RAD;
		k = tan(k);
		k = 1 + k * k;
		res = dot(-scene.ray, normalize(CONES[hit.id].dir)) * hit.dist - dot(ACTIVECAM.pos + PARAM->mvt - CONES[hit.id].pos, normalize(CONES[hit.id].dir));
		res = ((hit.pos - normalize(CONES[hit.id].pos)) - (k * normalize(CONES[hit.id].dir) * res)) * -1;
	}
	else if (hit.type == 2)
	{
		/*float3	base = CYLIND[hit.id].pos;
		res = hit.pos;

		res = rotate_matrix(45 * DEG2RAD, res);
		base.z = res.z;
		base = rotate_matrix(-45 * DEG2RAD, base);
		res = rotate_matrix(-45 * DEG2RAD, res);
		res -= base;*/
//		res = dot(-scene.ray, normalize(CYLIND[hit.id].dir) * hit.dist + \
//			dot(ACTIVECAM.pos + PARAM->mvt - CYLIND[hit.id].pos, normalize(CYLIND[hit.id].dir)));
//		res = hit.pos - CYLIND[hit.id].pos - normalize(CYLIND[hit.id].dir) * res;

	/*	res = normalize(hit.pos - CYLIND[hit.id].pos);
	// fonctionne pour cylindre aligné en Z
		if (dot(normalize(CYLIND[hit.id].dir), res) < 0)
		{
			res += normalize(CYLIND[hit.id].dir);
			res.z += 1;
		}
		else
		{
			res -= normalize(CYLIND[hit.id].dir);
			res.z += 1;
		}*/
		int		i = hit.id;
		float3	dir = rotate_obj(CYLIND[i].dir, CYLIND[i].pitch, CYLIND[i].yaw, 0);
		float16 ok = trans_matrix(dir, 90);
		//printf("the first\n0 : %f, 1 : %f, 2 : %f\n4 : %f, 5 : %f, 6 : %f\n8 : %f, 9 : %f, 10 : %f\n\n", ok[0], ok[1], ok[2], ok[4], ok[5], ok[6], ok[8], ok[9], ok[10]);
		res = apply_matrix(ok, hit.pos) - CYLIND[i].pos;
		res.z = 0;
		//ok = trans_matrix(dir, -90);
		//printf("the second\n0 : %f, 1 : %f, 2 : %f\n4 : %f, 5 : %f, 6 : %f\n8 : %f, 9 : %f, 10 : %f\n\n", ok[0], ok[1], ok[2], ok[4], ok[5], ok[6], ok[8], ok[9], ok[10]);
		res = apply_matrix(-ok, res);
		/*res = trans_matrix(dir, hit.pos);
		res = res - CYLIND[i].pos;
		res.z = 0;*/
		//res = trans_matrix(dir, res;
		/*
		nbase.dist = inter_cylinder(CYLIND[i].height, CYLIND[i].dir, CYLIND[i].radius, CYLIND[i].pos,  rotate_obj(scene.ray, -CYLIND[i].pitch, CYLIND[i].yaw, 0), (ACTIVECAM.pos + PARAM->mvt));
		nbase.pos = (ACTIVECAM.pos + PARAM->mvt) + normalize((rotate_obj(scene.ray, -CYLIND[i].pitch, -CYLIND[i].yaw, 0)) * nbase.dist);
		res = nbase.pos - CYLIND[i].pos;
		res.z = 0;
		res = rotate_obj(normalize(res), CYLIND[i].pitch, CYLIND[i].yaw, 0);*/
	}
	else if (hit.type == 4)
	{
		if (dot(PLANE[hit.id].normale, -scene.ray) < 0)
			res = -PLANE[hit.id].normale;
		else
			res = PLANE[hit.id].normale;
	}
	else if (hit.type == 5)
		res = hit.pos - SPHERE[hit.id].pos;
	return (normalize(res));
}

unsigned int			phong(const t_hit hit, const t_scene scene)
{
	int					i = -1;
	unsigned int		res_color = get_ambient(scene, get_obj_hue(scene, hit));
	float				tmp;
	float3				reflect = 0;

	t_light_ray			light_ray;
	t_hit				light_hit = hit_init();

	while (++i < PARAM->n_lights)
	{
		tmp = 0;
		light_ray.dir = LIGHT[i].pos - hit.pos;
		light_ray.dist = length(light_ray.dir);
		light_ray.dir = normalize(light_ray.dir);
		light_hit = ray_hit(hit.pos, light_ray.dir, scene);
		light_hit.id = i;
		light_hit.type = 3;
		if (light_hit.dist < light_ray.dist && light_hit.dist > 0)
		;
		else
		{
			tmp = dot(hit.normale, light_ray.dir);
			if (tmp > 0)
				res_color = color_diffuse(scene, hit, light_hit, res_color, tmp);
			reflect = normalize(((float)(2.0 * dot(hit.normale, light_ray.dir)) * hit.normale) - light_ray.dir);
			tmp = dot(reflect, -scene.ray);
			if (tmp > 0)
				res_color = color_specular(scene, hit, light_hit, res_color, tmp);
		}
	}
	return (res_color);
}

unsigned int			phong2(t_hit hit, t_scene scene)
{
	int					i = -1;
	unsigned int		res_color = get_ambient(scene, get_obj_hue(scene, hit));
	float				tmp = 0;
	float3				reflect = 0;

	t_light_ray			light_ray;
	t_hit				light_hit;

	while (++i < PARAM->n_lights)
	{
		light_ray.dir = LIGHT[i].pos - hit.pos;
		light_ray.dist = length(light_ray.dir);
		light_ray.dir = normalize(light_ray.dir);
		light_hit = ray_hit(hit.pos, light_ray.dir, scene);
		if (light_hit.dist < light_ray.dist && light_hit.dist > 0)
		;
		else
		{
			tmp = dot(hit.normale, light_ray.dir);
			if (tmp > 0)
				res_color = color_diffuse(scene, hit, light_hit, res_color, tmp);
			reflect = normalize(((float)(2.0 * dot(hit.normale, light_ray.dir)) * hit.normale) - light_ray.dir);
			tmp = dot(reflect, -scene.ray);
			if (tmp > 0)
				res_color = color_specular(scene, hit, light_hit, res_color, tmp);
		}
	}
	return (res_color);
}

unsigned int		bounce(const t_scene scene, const t_hit old_hit, const int depth)
{
	int				i = depth;
	unsigned int	color = 0;
	float3			reflex = 0;
	t_hit			new_hit;
	while (i > 0)
	{
		reflex = normalize(scene.ray - (2 * (float)dot(old_hit.normale, scene.ray) * old_hit.normale));
		new_hit.dist = MAX_DIST;
		new_hit = ray_hit(old_hit.pos, reflex, scene);
		if (new_hit.dist > 0 && new_hit.dist < MAX_DIST)
		{
			new_hit.pos = (new_hit.dist * reflex) + old_hit.pos;
			new_hit.normale = get_hit_normale(scene, new_hit);
			new_hit.pos = new_hit.pos + ((new_hit.dist / 100) * new_hit.normale);
			color += 0.1 * phong2(new_hit, scene);
		}
		i--;
	}
	return (color);
}

unsigned int	get_pixel_color(const t_scene scene)
{
	t_hit			hit;
	int				depth = PARAM->depth;
	unsigned int	color  = 0;
	unsigned int	bounce_color = 0;

	hit.dist = MAX_DIST;
	hit = ray_hit((ACTIVECAM.pos + PARAM->mvt), scene.ray, scene);
	if (hit.dist > 0 && hit.dist < MAX_DIST) // ajout d'une distance max pour virer acnee mais pas fiable a 100%
	{
		hit.pos = (hit.dist * scene.ray) + (ACTIVECAM.pos + PARAM->mvt);
		hit.normale = get_hit_normale(scene, hit);
		hit.pos = hit.pos + ((hit.dist / 100) * hit.normale);
		color = phong(hit, scene);
		if (depth > 0)
			bounce_color = bounce(scene, hit, depth);
		return (color + bounce_color);
//		return (blend_add(color, 0.8*bounce_color));
	}
	return (get_ambient(scene, BACKCOLOR));
}

//	if ((scene.pix.x == 175 || scene.pix.x == 525 || scene.pix.x == 845) && scene.pix.y == 370)
//		printf("light.id = %d | light.color = %08x\n", light_hit.id, LIGHT[light_hit.id].color);
//		printf("l_hit.id = %d l_hit.type = %d l_hit.dist = %f\n", light_hit.id, light_hit.type, light_hit.dist);

__kernel void	ray_trace(__global		char		*output,
						  				t_param		param,
						  __constant	t_cam		*cameras,
						  __constant	t_cone		*cones,
						  __constant	t_cylinder	*cylinders,
						  __constant	t_light		*lights,
						  __constant	t_plane		*planes,
						  __constant	t_sphere	*spheres,
						  __global		t_hit		*target_obj)
{
	t_scene		scene = grab_data(cameras, cones, cylinders, lights, planes, spheres, param);
	scene.pix.x = get_global_id(0);
	scene.pix.y = get_global_id(1);
	int			id = scene.pix.x + (PARAM->win_w * scene.pix.y); // NE PAS VIRER ID CAR BESOIN DANS MACRO OUTPUTE
	scene.ray = get_ray_cam(ACTIVECAM, scene, scene.pix.x ,scene.pix.y);
	if (scene.pix.x == PARAM->mou_x && scene.pix.y == PARAM->mou_y)
		*target_obj = ray_hit((ACTIVECAM.pos + PARAM->mvt), scene.ray, scene);
	OUTPUTE = get_pixel_color(scene);
}


Add isnan check to the cross entropy error criterion kernel

#pragma OPENCL EXTENSION cl_khr_fp64 : enable

typedef float Scalar;

Scalar sigmoid(Scalar x) {
    return (Scalar)1.0/((Scalar)1.0 + exp(-x));
}

kernel void sigmoidPredict(global Scalar *x) {
    size_t i = get_global_id(0);
    x[i] = sigmoid(x[i]);
}

kernel void sigmoidFeedforward(global Scalar *x, global Scalar *derivative) {
    size_t i = get_global_id(0);
    Scalar y = sigmoid(x[i]);
    x[i] = y;
    derivative[i] = y*((Scalar)1.0 - y);
}

kernel void reluPredict(global Scalar *x) {
    size_t i = get_global_id(0);
    x[i] = max(x[i], (Scalar)0.0);
}

kernel void reluFeedforward(global Scalar *x, global Scalar *derivative) {
    size_t i = get_global_id(0);
    if (x[i] > 0.0) {
        derivative[i] = 1.0;
    } else {
        x[i] = 0.0;
        derivative[i] = 0.0;
    }
}

kernel void meanSquaredError(global Scalar *prediction, global Scalar *y, global Scalar *output) {
    size_t i = get_global_id(0);
    Scalar diff = y[i] - prediction[i];
    output[i] += diff * diff;
}

kernel void crossEntropyError(global Scalar *prediction, global Scalar *y, global Scalar *output) {
    size_t i = get_global_id(0);
    Scalar err = -(y[i]*log(prediction[i]) + ((Scalar)1.0 - y[i])*log((Scalar)1.0 - prediction[i]));
    output[i] += isnan(err)? (Scalar)0.0 : err;
}

// The "responsibility" of the last layer with MSE criterion.
kernel void computeMSELayerError(global Scalar *activation, global Scalar *y, global Scalar *derivative) {
    size_t i = get_global_id(0);
    derivative[i] = (activation[i] - y[i]) * derivative[i];
}

// The "responsibility" of the last layer with cross entropy error.
kernel void computeCrossEntropyLayerError(global Scalar *activation, global Scalar *y, global Scalar *derivative) {
    size_t i = get_global_id(0);
    derivative[i] = activation[i] - y[i];
}

// The "responsibility" of a layer in a NN (except for the last one).
// error = (W_next'*error_next .* derivative)
kernel void computeError(global Scalar *nextLayerWeights, global Scalar *nextLayerError, const uint nextLayerNeuronCount, const uint columns, global Scalar *derivative) {
    size_t i = get_global_id(0);
    Scalar sum = 0;
    size_t offset = i; // index into the matrix column
    for (size_t j = 0; j < nextLayerNeuronCount; j++, offset+=columns) {
        sum += nextLayerWeights[offset] * nextLayerError[j];
    }
    derivative[i] *= sum;
}

// gradients = error * input'
// bias gradients are just added
kernel void computeWeightGradient(global Scalar *errorTerm, global Scalar *input, global Scalar *weightGradients) {
    size_t row = get_global_id(0);
    size_t column = get_global_id(1);
    size_t columns = get_global_size(1);
    weightGradients[row*columns + column] += errorTerm[row] * input[column];
}

kernel void evaluateClassification(global Scalar *output, const uint n, const uint size, global ushort *labels, global uchar *dest) {
    size_t part = n;//Later: get_global_id(0);

    size_t i = 0, end = i + size;
    Scalar maxValue = output[i];
    size_t maxIndex = i;
    for (++i; i < end; ++i) {
        if (output[i] > maxValue) {
            maxValue = output[i];
            maxIndex = i;
        }
    }
    dest[part] = maxIndex == labels[part];
}

/*
TODO:

float parkMillerRandom(int *seed) {
    double const a    = 16807;      //ie 7**5
    double const m    = 2147483647; //ie 2**31-1
    double const reciprocal_m = 1.0/m;

    double temp = *seed * a;
    seed = (int)(temp - m * floor(temp * reciprocal_m));
    return float(temp * reciprocal_m);
}

kernel void dropout(global Scalar *x, global int* seeds, const float discardProbability) {
    size_t i = get_global_id(0);
    int seed = seeds[i];
    x[i] = parkMillerRandom(&seed);
    seeds[i] = seed;
}*/

#pragma OPENCL EXTENSION cl_khr_fp64 : enable

typedef float Scalar;

Scalar sigmoid(Scalar x) {
    return (Scalar)1.0/((Scalar)1.0 + exp(-x));
}

kernel void sigmoidPredict(global Scalar *x) {
    size_t i = get_global_id(0);
    x[i] = sigmoid(x[i]);
}

kernel void sigmoidFeedforward(global Scalar *x, global Scalar *derivative) {
    size_t i = get_global_id(0);
    Scalar y = sigmoid(x[i]);
    x[i] = y;
    derivative[i] = y*((Scalar)1.0 - y);
}

kernel void reluPredict(global Scalar *x) {
    size_t i = get_global_id(0);
    x[i] = max(x[i], (Scalar)0.0);
}

kernel void reluFeedforward(global Scalar *x, global Scalar *derivative) {
    size_t i = get_global_id(0);
    if (x[i] > 0.0) {
        derivative[i] = 1.0;
    } else {
        x[i] = 0.0;
        derivative[i] = 0.0;
    }
}

kernel void meanSquaredError(global Scalar *prediction, global Scalar *y, global Scalar *output) {
    size_t i = get_global_id(0);
    Scalar diff = y[i] - prediction[i];
    output[i] += diff * diff;
}

kernel void crossEntropyError(global Scalar *prediction, global Scalar *y, global Scalar *output) {
    size_t i = get_global_id(0);
    output[i] += -(y[i]*log(prediction[i]) + ((Scalar)1.0 - y[i])*log((Scalar)1.0 - prediction[i]));
}

// The "responsibility" of the last layer with MSE criterion.
kernel void computeMSELayerError(global Scalar *activation, global Scalar *y, global Scalar *derivative) {
    size_t i = get_global_id(0);
    derivative[i] = (activation[i] - y[i]) * derivative[i];
}

// The "responsibility" of the last layer with cross entropy error.
kernel void computeCrossEntropyLayerError(global Scalar *activation, global Scalar *y, global Scalar *derivative) {
    size_t i = get_global_id(0);
    derivative[i] = activation[i] - y[i];
}

// The "responsibility" of a layer in a NN (except for the last one).
// error = (W_next'*error_next .* derivative)
kernel void computeError(global Scalar *nextLayerWeights, global Scalar *nextLayerError, const uint nextLayerNeuronCount, const uint columns, global Scalar *derivative) {
    size_t i = get_global_id(0);
    Scalar sum = 0;
    size_t offset = i; // index into the matrix column
    for (size_t j = 0; j < nextLayerNeuronCount; j++, offset+=columns) {
        sum += nextLayerWeights[offset] * nextLayerError[j];
    }
    derivative[i] *= sum;
}

// gradients = error * input'
// bias gradients are just added
kernel void computeWeightGradient(global Scalar *errorTerm, global Scalar *input, global Scalar *weightGradients) {
    size_t row = get_global_id(0);
    size_t column = get_global_id(1);
    size_t columns = get_global_size(1);
    weightGradients[row*columns + column] += errorTerm[row] * input[column];
}

kernel void evaluateClassification(global Scalar *output, const uint n, const uint size, global ushort *labels, global uchar *dest) {
    size_t part = n;//Later: get_global_id(0);

    size_t i = 0, end = i + size;
    Scalar maxValue = output[i];
    size_t maxIndex = i;
    for (++i; i < end; ++i) {
        if (output[i] > maxValue) {
            maxValue = output[i];
            maxIndex = i;
        }
    }
    dest[part] = maxIndex == labels[part];
}

/*
TODO:

float parkMillerRandom(int *seed) {
    double const a    = 16807;      //ie 7**5
    double const m    = 2147483647; //ie 2**31-1
    double const reciprocal_m = 1.0/m;

    double temp = *seed * a;
    seed = (int)(temp - m * floor(temp * reciprocal_m));
    return float(temp * reciprocal_m);
}

kernel void dropout(global Scalar *x, global int* seeds, const float discardProbability) {
    size_t i = get_global_id(0);
    int seed = seeds[i];
    x[i] = parkMillerRandom(&seed);
    seeds[i] = seed;
}*/


finite_sum_opencl uses better constant memory.

/*
  finite_sum_opencl.cl

  OpenCL code for computing the finite sum in the computation of the Riemann
  theta function.
*/

/*
 */
#define PI 3.141592653589793

float exppart(int, __constant const float*, __constant const float*,
	      __constant const float*, const int,  __constant const float*);

float normpart(int, __constant const float*, __constant const float*, const int,
	       __constant const float*);

/*
  Given integer vector S[i], compte the exppart of the sum.
*/
float exppart(int i,
	      __constant const float* X,
	      __constant const float* intshift,
	      __constant const float* x,
	      const int g,
	      __constant const float* S)
{
  // perform dot product of matrix mult
  float sum = 0;
  float v_j, Xw_j;
  for (int j=0; j<g; j++) {
    // jth component of a-intshift
    v_j = S[i*g+j]-intshift[j];

    // jth component of (1/2) X*(a-intshift) + x
    Xw_j = 0;
    for (int k=0; k<g; k++) {
      Xw_j += 0.5 * X[j*g+k] * (S[i*g+k]-intshift[k]);
    }
    Xw_j += x[j];

    // add the jth component to the dot product container
    sum += v_j*Xw_j;
  }

  return 2*PI*sum;
}

/*
  Given integer vector S[i], compte the exppart of the sum.
*/
float normpart(int i,
	       __constant const float* T,
	       __constant const float* fracshift,
	       const int g,
	       __constant const float* S)
{
  float sum = 0;
  float v_j;

  // loop over elements of two vectors
  for (int j=0; j<g; j++){
    // calculate jth component of v=T(a+fracshift)
    v_j = 0;
    for (int k=0; k<g; k++) {
      v_j += T[j*g+k] * (S[i*g+k]+fracshift[k]);
    }

    sum += v_j*v_j;
  }

  return -PI*sum;
}

__kernel void
finite_sum_without_derivs(__constant const float* X,
			  __constant const float* T,
			  __constant const float* x,
			  __constant const float* intshift,
			  __constant const float* fracshift,
			  const int g,
			  __constant const float* S,
			  __global float* fsum_real,   // accum vectors
			  __global float* fsum_imag)   // accum vectors
{
  float ept, npt, cpart, spart;
  int i;
  i = get_global_id(0);

  // compute exponential and norm parts
  ept = exppart(i,X,intshift,x,g,S);
  npt = exp(normpart(i,T,fracshift,g,S));

  // split up into real and imaginary (cosine and sine) parts
  cpart = npt * cos(ept);
  spart = npt * sin(ept);

  // add to real and imaginary parts of summation
  fsum_real[i] = cpart;
  fsum_imag[i] = spart;
}

/*
  finite_sum_opencl.cl

  OpenCL code for computing the finite sum in the computation of the Riemann
  theta function.
*/

/*
 */
#define PI 3.141592653589793

float exppart(int, __constant float*, __constant float*,
	      __constant float*, int,  __constant float*);

float normpart(int, __constant float*, __constant float*, int,
	       __constant float*);

/*
  Given integer vector S[i], compte the exppart of the sum.
*/
float exppart(int i,
	      __constant float* X,
	      __constant float* intshift,
	      __constant float* x,
	      int g,
	      __constant float* S)
{
  // perform dot product of matrix mult
  float sum = 0;
  float v_j, Xw_j;
  for (int j=0; j<g; j++) {
    // jth component of a-intshift
    v_j = S[i*g+j]-intshift[j];

    // jth component of (1/2) X*(a-intshift) + x
    Xw_j = 0;
    for (int k=0; k<g; k++) {
      Xw_j += 0.5 * X[j*g+k] * (S[i*g+k]-intshift[k]);
    }
    Xw_j += x[j];

    // add the jth component to the dot product container
    sum += v_j*Xw_j;
  }

  return 2*PI*sum;
}

/*
  Given integer vector S[i], compte the exppart of the sum.
*/
float normpart(int i,
	       __constant float* T,
	       __constant float* fracshift,
	       int g,
	       __constant float* S)
{
  float sum = 0;
  float v_j;

  // loop over elements of two vectors
  for (int j=0; j<g; j++){
    // calculate jth component of v=T(a+fracshift)
    v_j = 0;
    for (int k=0; k<g; k++) {
      v_j += T[j*g+k] * (S[i*g+k]+fracshift[k]);
    }

    sum += v_j*v_j;
  }

  return -PI*sum;
}

__kernel void
finite_sum_without_derivs(__constant float* X,
			  __constant float* T,
			  __constant float* x,
			  __constant float* intshift,
			  __constant float* fracshift,
			  int g,
			  __constant float* S,
			  __global float* fsum_real,   // accum vectors
			  __global float* fsum_imag)   // accum vectors
{
  float ept, npt, cpart, spart;
  int i;
  i = get_global_id(0);

  // compute exponential and norm parts
  ept = exppart(i,X,intshift,x,g,S);
  npt = exp(normpart(i,T,fracshift,g,S));

  // split up into real and imaginary (cosine and sine) parts
  cpart = npt * cos(ept);
  spart = npt * sin(ept);

  // add to real and imaginary parts of summation
  fsum_real[i] = cpart;
  fsum_imag[i] = spart;
}


Fixed wrong data type in OpenCL transform

/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#define NEAREST transform_n
#define BILINEAR transform_b
#define LOWER transform_l

void calc_transf_inverse(float* txo, __global const float* txi)
{
#if PERSPECTIVE
    txo[0] =   txi[4]*txi[8] - txi[5]*txi[7];
    txo[1] = -(txi[1]*txi[8] - txi[2]*txi[7]);
    txo[2] =   txi[1]*txi[5] - txi[2]*txi[4];

    txo[3] = -(txi[3]*txi[8] - txi[5]*txi[6]);
    txo[4] =   txi[0]*txi[8] - txi[2]*txi[6];
    txo[5] = -(txi[0]*txi[5] - txi[2]*txi[3]);

    txo[6] =   txi[3]*txi[7] - txi[4]*txi[6];
    txo[7] = -(txi[0]*txi[7] - txi[1]*txi[6]);
    txo[8] =   txi[0]*txi[4] - txi[1]*txi[3];

    float det = txi[0]*txo[0] + txi[1]*txo[3] + txi[2]*txo[6];

    txo[0] /= det; txo[1] /= det; txo[2] /= det;
    txo[3] /= det; txo[4] /= det; txo[5] /= det;
    txo[6] /= det; txo[7] /= det; txo[8] /= det;
#else
    float det = txi[0]*txi[4] - txi[1]*txi[3];

    txo[0] = txi[4] / det;
    txo[1] = txi[3] / det;
    txo[3] = txi[1] / det;
    txo[4] = txi[0] / det;

    txo[2] = txi[2] * -txo[0] + txi[5] * -txo[1];
    txo[5] = txi[2] * -txo[3] + txi[5] * -txo[4];
#endif
}

__kernel
void transform_kernel(__global T *d_out, const KParam out,
                      __global const T *d_in, const KParam in,
                      __global const float *c_tmat, const KParam tf,
                      const int nimages, const int ntransforms,
                      const int blocksXPerImage)
{
    // Compute which image set
    const int setId = get_group_id(0) / blocksXPerImage;
    const int blockIdx_x = get_group_id(0) - setId * blocksXPerImage;

    // Get thread indices
    const int xx = get_local_id(0) + blockIdx_x * get_local_size(0);
    const int yy = get_global_id(1);

    if(xx >= out.dims[0] * nimages || yy >= out.dims[1] * ntransforms)
        return;

    // Index of channel of images and transform
    //int i_idx = xx / out.dims[0];
    const int t_idx = yy / out.dims[1];

    const int limages = min((int)out.dims[2] - setId * nimages, nimages);

    // Index in local channel -> This is output index
    const int xido = xx; // - i_idx * out.dims[0];
    const int yido = yy - t_idx * out.dims[1];

    // Global offset
    //          Offset for transform channel + Offset for image channel.
    d_out += t_idx * nimages * out.strides[2] + setId * nimages * out.strides[2];
    d_in  += setId * nimages * in.strides[2] + in.offset;

    // Transform is in global memory.
    // Needs offset to correct transform being processed.
    __global const float *tmat_ptr = c_tmat + t_idx * TRANSF_LEN;
    float tmat[TRANSF_LEN];

    // We expect a inverse transform matrix by default
    // If it is an forward transform, then we need its inverse
    if(INVERSE == 1) {
        #pragma unroll 3
        for(int i = 0; i < TRANSF_LEN; i++)
            tmat[i] = tmat_ptr[i];
    } else {
        calc_transf_inverse(tmat, tmat_ptr);
    }

    if (xido >= out.dims[0] && yido >= out.dims[1]) return;

    INTERP(d_out, out, d_in, in, tmat, xido, yido, limages);
}

/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#define NEAREST transform_n
#define BILINEAR transform_b
#define LOWER transform_l

void calc_transf_inverse(float* txo, __global const float* txi)
{
#if PERSPECTIVE
    txo[0] =   txi[4]*txi[8] - txi[5]*txi[7];
    txo[1] = -(txi[1]*txi[8] - txi[2]*txi[7]);
    txo[2] =   txi[1]*txi[5] - txi[2]*txi[4];

    txo[3] = -(txi[3]*txi[8] - txi[5]*txi[6]);
    txo[4] =   txi[0]*txi[8] - txi[2]*txi[6];
    txo[5] = -(txi[0]*txi[5] - txi[2]*txi[3]);

    txo[6] =   txi[3]*txi[7] - txi[4]*txi[6];
    txo[7] = -(txi[0]*txi[7] - txi[1]*txi[6]);
    txo[8] =   txi[0]*txi[4] - txi[1]*txi[3];

    T det = txi[0]*txo[0] + txi[1]*txo[3] + txi[2]*txo[6];

    txo[0] /= det; txo[1] /= det; txo[2] /= det;
    txo[3] /= det; txo[4] /= det; txo[5] /= det;
    txo[6] /= det; txo[7] /= det; txo[8] /= det;
#else
    T det = txi[0]*txi[4] - txi[1]*txi[3];

    txo[0] = txi[4] / det;
    txo[1] = txi[3] / det;
    txo[3] = txi[1] / det;
    txo[4] = txi[0] / det;

    txo[2] = txi[2] * -txo[0] + txi[5] * -txo[1];
    txo[5] = txi[2] * -txo[3] + txi[5] * -txo[4];
#endif
}

__kernel
void transform_kernel(__global T *d_out, const KParam out,
                      __global const T *d_in, const KParam in,
                      __global const float *c_tmat, const KParam tf,
                      const int nimages, const int ntransforms,
                      const int blocksXPerImage)
{
    // Compute which image set
    const int setId = get_group_id(0) / blocksXPerImage;
    const int blockIdx_x = get_group_id(0) - setId * blocksXPerImage;

    // Get thread indices
    const int xx = get_local_id(0) + blockIdx_x * get_local_size(0);
    const int yy = get_global_id(1);

    if(xx >= out.dims[0] * nimages || yy >= out.dims[1] * ntransforms)
        return;

    // Index of channel of images and transform
    //int i_idx = xx / out.dims[0];
    const int t_idx = yy / out.dims[1];

    const int limages = min((int)out.dims[2] - setId * nimages, nimages);

    // Index in local channel -> This is output index
    const int xido = xx; // - i_idx * out.dims[0];
    const int yido = yy - t_idx * out.dims[1];

    // Global offset
    //          Offset for transform channel + Offset for image channel.
    d_out += t_idx * nimages * out.strides[2] + setId * nimages * out.strides[2];
    d_in  += setId * nimages * in.strides[2] + in.offset;

    // Transform is in global memory.
    // Needs offset to correct transform being processed.
    __global const float *tmat_ptr = c_tmat + t_idx * TRANSF_LEN;
    float tmat[TRANSF_LEN];

    // We expect a inverse transform matrix by default
    // If it is an forward transform, then we need its inverse
    if(INVERSE == 1) {
        #pragma unroll
        for(int i = 0; i < TRANSF_LEN; i++)
            tmat[i] = tmat_ptr[i];
    } else {
        calc_transf_inverse(tmat, tmat_ptr);
    }

    if (xido >= out.dims[0] && yido >= out.dims[1]) return;

    INTERP(d_out, out, d_in, in, tmat, xido, yido, limages);
}


clang/test/SemaOpenCL/overload_addrspace_resolution.cl: Appease MS mangler to specify triple=x86_64-unknown.

git-svn-id: ffe668792ed300d6c2daa1f6eba2e0aa28d7ec6c@297530 91177308-0d34-0410-b5e6-96231b3b80d8

// RUN: %clang_cc1 -cl-std=CL2.0 -emit-llvm -o - -triple x86_64-unknown-unknown %s | FileCheck %s

void __attribute__((overloadable)) foo(global int *a, global int *b);
void __attribute__((overloadable)) foo(generic int *a, generic int *b);
void __attribute__((overloadable)) bar(generic int *global *a, generic int *global *b);
void __attribute__((overloadable)) bar(generic int *generic *a, generic int *generic *b);

void kernel ker() {
  global int *a;
  global int *b;
  generic int *c;
  local int *d;
  generic int *generic *gengen;
  generic int *local *genloc;
  generic int *global *genglob;
  // CHECK: call void @_Z3fooPU8CLglobaliS0_(i32* undef, i32* undef)
  foo(a, b);
  // CHECK: call void @_Z3fooPU9CLgenericiS0_(i32* undef, i32* undef)
  foo(b, c);
  // CHECK: call void @_Z3fooPU9CLgenericiS0_(i32* undef, i32* undef)
  foo(a, d);

  // CHECK: call void @_Z3barPU9CLgenericPU9CLgenericiS2_(i32** undef, i32** undef)
  bar(gengen, genloc);
  // CHECK: call void @_Z3barPU9CLgenericPU9CLgenericiS2_(i32** undef, i32** undef)
  bar(gengen, genglob);
  // CHECK: call void @_Z3barPU8CLglobalPU9CLgenericiS2_(i32** undef, i32** undef)
  bar(genglob, genglob);
}

// RUN: %clang_cc1 -cl-std=CL2.0 -emit-llvm -o - %s | FileCheck %s

void __attribute__((overloadable)) foo(global int *a, global int *b);
void __attribute__((overloadable)) foo(generic int *a, generic int *b);
void __attribute__((overloadable)) bar(generic int *global *a, generic int *global *b);
void __attribute__((overloadable)) bar(generic int *generic *a, generic int *generic *b);

void kernel ker() {
  global int *a;
  global int *b;
  generic int *c;
  local int *d;
  generic int *generic *gengen;
  generic int *local *genloc;
  generic int *global *genglob;
  // CHECK: call void @_Z3fooPU8CLglobaliS0_(i32* undef, i32* undef)
  foo(a, b);
  // CHECK: call void @_Z3fooPU9CLgenericiS0_(i32* undef, i32* undef)
  foo(b, c);
  // CHECK: call void @_Z3fooPU9CLgenericiS0_(i32* undef, i32* undef)
  foo(a, d);

  // CHECK: call void @_Z3barPU9CLgenericPU9CLgenericiS2_(i32** undef, i32** undef)
  bar(gengen, genloc);
  // CHECK: call void @_Z3barPU9CLgenericPU9CLgenericiS2_(i32** undef, i32** undef)
  bar(gengen, genglob);
  // CHECK: call void @_Z3barPU8CLglobalPU9CLgenericiS2_(i32** undef, i32** undef)
  bar(genglob, genglob);
}


fix typo for MIOpenConv1x1S.cl

fix typo for MIOpenConv1x1S.cl

/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/

#define _FLOAT float
#define _FLOAT2 float2
#define _FLOAT4 float4
#define _FLOAT8 float8

#ifndef FLT_MAX
#define FLT_MAX 3.402823466e+38F /* max value */
#endif

#define UNUSED __attribute__((__unused__))

#define DBG_OUT_OF_RNGE 0

// calculating the size of the area for weights prefetch

__attribute__((always_inline)) uint iDiv(uint v, uint d)
{
    uint r = (uint)((float)v * (1.0f / (float)d) + 0.00001f);
    return (r);
}

__attribute__((always_inline)) uint iMod(uint v, uint u, uint d)
{
    uint r = v - mul24(u, d);
    return (r);
}

__attribute__((reqd_work_group_size(MLO_GRP_SZ0, MLO_GRP_SZ1, MLO_GRP_SZ2))) __kernel void
MIOpenConv1x1(const __global _FLOAT* __restrict in_ptr,
              __constant _FLOAT* __restrict wei_ptr,
#if MLO_CONV_BIAS
              const __global _FLOAT* __restrict bias,
#endif
              __global _FLOAT* __restrict out_ptr,
              UNUSED _FLOAT dummy_val // nothing
              )
{

    _FLOAT weights[MLO_N_LCL_OUT_MAPS][MLO_N_LCL_IN_MAPS];

    uint gbl_id0  = get_global_id(0);
    uint batch_id = gbl_id0 / MLO_MAP_SZ4; // batch
    uint pos      = gbl_id0 % MLO_MAP_SZ4;

    uint out_grp_block = get_group_id(1); // block of outputs for the entire group
    uint out_id        = out_grp_block * MLO_N_LCL_OUT_MAPS;

    uint gbl_in_off = batch_id * MLO_IN_BATCH_STRIDE + pos * MLO_READ_UNIT;

    uint wei_off = out_id *
#if MLO_DIR_FORWARD == 1
                   MLO_WEI_BSTRIDE
#else
                   MLO_WEI_CHANNEL_STRIDE
#endif
        ;

    _FLOAT accum[MLO_N_LCL_OUT_MAPS][MLO_READ_UNIT];
    _FLOAT dat[MLO_N_LCL_IN_MAPS][MLO_READ_UNIT];

    for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            accum[o][i] = 0;
        }
    }

    for(uint ci = 0; ci < MLO_CLOOP0; ++ci,
             // move input offset
                                      gbl_in_off += MLO_N_LCL_IN_MAPS * MLO_IN_CHANNEL_STRIDE,

             // move weights offset
                                      wei_off += MLO_N_LCL_IN_MAPS *
#if MLO_DIR_FORWARD == 1
                                                 MLO_WEI_CHANNEL_STRIDE
#else
                                                 MLO_WEI_BSTRIDE
#endif
        )
    {
        // read weights

        __constant _FLOAT* w1 = wei_ptr + wei_off;

        for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o,
                 w1 +=
#if MLO_DIR_FORWARD == 1
                                                MLO_WEI_BSTRIDE
#else
                                                MLO_WEI_CHANNEL_STRIDE
#endif
            )
        {
            __constant _FLOAT* w2 = w1;
            for(uint c = 0; c < MLO_N_LCL_IN_MAPS; ++c,
                     w2 +=
#if MLO_DIR_FORWARD == 1
                                                  MLO_WEI_CHANNEL_STRIDE
#else
                                                  MLO_WEI_BSTRIDE
#endif
                )
            {
                weights[o][c] = *w2;
#if DBG_OUT_OF_RNGE
                if(wei_off2 >= MLO_N_INPUTS * MLO_N_OUTPUTS)
                {
                    printf("K:oor: weights\n");
                }
#endif
            }
        }

        // convolve with all weights
        // read data
        // Shader compiler will use      GLOAL_LOAD_DWORD's OFFSET for *(ptr+index) access
        // Shader compiler will not use  GLOAL_LOAD_DWORD's OFFSET for ptr[index] access

        __global const float* p = in_ptr + gbl_in_off;

        for(uint j = 0; j < MLO_N_LCL_IN_MAPS; j++)
        {
            for(uint i = 0; i < MLO_READ_UNIT; ++i)
            {
                dat[j][i] = *(p + i);
#if DBG_OUT_OF_RNGE
                if(gbl_in_off1 + i >= MLO_IN_BATCH_STRIDE * MLO_BATCH_SZ)
                {
                    printf("K:oor: inputs\n");
                }
#endif
            }
            p += MLO_IN_CHANNEL_STRIDE;
        }

        // convolve
        for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
        {
            for(uint c = 0; c < MLO_N_LCL_IN_MAPS; ++c)
            {
                for(uint i = 0; i < MLO_READ_UNIT; ++i)
                {
                    accum[o][i] += dat[c][i] * weights[o][c];
                }
            }
        }
    }

    uint gbl_out_off =
        batch_id * MLO_OUT_BATCH_STRIDE + pos * MLO_READ_UNIT + out_id * MLO_OUT_CHANNEL_STRIDE;
    __global _FLOAT* q = out_ptr + gbl_out_off;

    for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o, q += MLO_OUT_CHANNEL_STRIDE)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            *(q + i) = accum[o][i];
        }
    }
}

/************************************************************************
stride and padding
*************************************************************************/
__attribute__((reqd_work_group_size(MLO_GRP_SZ0, MLO_GRP_SZ1, MLO_GRP_SZ2))) __kernel void
MIOpenConv1x1pquv(const __global _FLOAT* __restrict in_ptr,
                  __constant _FLOAT* __restrict wei_ptr,
#if MLO_CONV_BIAS
                  const __global _FLOAT* __restrict bias,
#endif
                  __global _FLOAT* __restrict out_ptr,
                  UNUSED _FLOAT dummy_val // nothing
                  )
{

    _FLOAT weights[MLO_N_LCL_OUT_MAPS][MLO_N_LCL_IN_MAPS];

    uint gbl_id0 = get_global_id(0);

    uint batch_id  = gbl_id0 / MLO_MAP_SZ4; // batch
    uint pos       = gbl_id0 % MLO_MAP_SZ4;
    uint pos_out_y = pos / MLO_OUT_WIDTH4;
    uint pos_out_x = pos % MLO_OUT_WIDTH4;

#if MLO_DIR_FORWARD == 1
    uint pos_in_y = pos_out_y * MLO_FILTER_STRIDE1;
    uint pos_in_x = pos_out_x * MLO_FILTER_STRIDE0;
#else
    uint pos_in_y = pos_out_y; /// MLO_FILTER_STRIDE1;   - divided already
    uint pos_in_x = pos_out_x; // MLO_FILTER_STRIDE0;  - divided already
#endif

    uint out_grp_block = get_group_id(1); // block of outputs for the entire group
    uint out_id        = out_grp_block * MLO_N_LCL_OUT_MAPS;

    uint gbl_in_off =
        batch_id * MLO_IN_BATCH_STRIDE + pos_in_y * MLO_IN_STRIDE + pos_in_x * MLO_READ_UNIT;
    //	bool vis = (pos_in_y < MLO_IN_HEIGHT);
    //	gbl_in_off = (vis) ? gbl_in_off : 0;

    uint wei_off = out_id *
#if MLO_DIR_FORWARD == 1
                   MLO_WEI_BSTRIDE
#else
                   MLO_WEI_CHANNEL_STRIDE
#endif
        ;

    _FLOAT accum[MLO_N_LCL_OUT_MAPS][MLO_READ_UNIT];
    _FLOAT dat[MLO_N_LCL_IN_MAPS][MLO_READ_UNIT];

    for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            accum[o][i] = 0;
        }
    }

    const __global _FLOAT* i_ptr = in_ptr + gbl_in_off;
    __constant _FLOAT* w_ptr     = wei_ptr + wei_off;
    for(uint ci = 0; ci < MLO_CLOOP0; ++ci)
    {

        // convolve with all weights
        // read data

        for(uint j = 0; j < MLO_N_LCL_IN_MAPS; ++j)
        {
            uint i = 0;
#if MLO_READ_UNIT > 1
            for(; i < MLO_READ_UNIT - 1; ++i)
            {
                uint off = i
#if MLO_DIR_FORWARD == 1
                           * MLO_FILTER_STRIDE0
#endif
                    ;
                dat[j][i] = *(i_ptr + off);
            }
#endif

            for(; i < MLO_READ_UNIT; ++i)
            {
                //				vis &= (pos_in_x + i*MLO_FILTER_STRIDE0 <
                // MLO_IN_WIDTH);
                uint off = i
#if MLO_DIR_FORWARD == 1
                           * MLO_FILTER_STRIDE0
#endif
                    ;
                //				off = (vis) ? off : 0;
                _FLOAT val = *(i_ptr + off);
                dat[j][i]  = val;
                //              dat[j][i] = (vis)? dat[j][i] : 0;
            }

            i_ptr += MLO_IN_CHANNEL_STRIDE;
        }
        // read weights
        __constant _FLOAT* w_ptr0 = w_ptr;

        for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
        {

            __constant _FLOAT* w_ptr1 = w_ptr0;

            for(uint c = 0; c < MLO_N_LCL_IN_MAPS; ++c)
            {
                weights[o][c] = *w_ptr1;
                w_ptr1 +=
#if MLO_DIR_FORWARD == 1
                    MLO_WEI_CHANNEL_STRIDE
#else
                    MLO_WEI_BSTRIDE
#endif
                    ;
            }

            w_ptr0 +=
#if MLO_DIR_FORWARD == 1
                MLO_WEI_BSTRIDE
#else
                MLO_WEI_CHANNEL_STRIDE
#endif
                ;
        }

        w_ptr += MLO_N_LCL_IN_MAPS *
#if MLO_DIR_FORWARD == 1
                 MLO_WEI_CHANNEL_STRIDE
#else
                 MLO_WEI_BSTRIDE
#endif
            ;
        // convolve
        for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
        {
            for(uint c = 0; c < MLO_N_LCL_IN_MAPS; ++c)
            {
                for(uint i = 0; i < MLO_READ_UNIT; ++i)
                {
                    accum[o][i] += dat[c][i] * weights[o][c];
#if 0
				if (pos_out_y == 2 && pos_out_x == 0)
				{
					printf((__constant char *)"K:c: %f %f %f %f\n",
					accum[o][i],
					dat[c][i] * weights[o][c],
					dat[c][i],
					weights[o][c]
					);
				}
#endif
                }
            }
        }
    }

    uint out_y = pos_out_y
#if MLO_DIR_FORWARD == 0
                 * MLO_FILTER_STRIDE1
#endif
        ;
    uint out_x = pos_out_x
#if MLO_DIR_FORWARD == 0
                 * MLO_FILTER_STRIDE0
#endif
        ;

    uint gbl_out_off = batch_id * MLO_OUT_BATCH_STRIDE + out_id * MLO_OUT_CHANNEL_STRIDE +
                       out_y * MLO_OUT_STRIDE + out_x * MLO_READ_UNIT;

    __global _FLOAT* q = out_ptr + gbl_out_off;

    for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o, q += MLO_OUT_CHANNEL_STRIDE)
    {

        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            __global _FLOAT* q1 = q;
            q1 += i
#if MLO_DIR_FORWARD == 0

                  * MLO_FILTER_STRIDE0;
#endif
            ;
            *q1 = accum[o][i];

#if MLO_DIR_FORWARD == 0
            for(uint s = 1; s < MLO_FILTER_STRIDE0; ++s)
            {
#if MLO_HORIZ_ALIGNED == 0
                if(out_x + s < MLO_OUT_WIDTH)
#endif
                {
                    *(q1 + s) = 0;
                }
            }
#endif
        }

#if MLO_DIR_FORWARD == 0
        __global _FLOAT* q2 = q;
        for(uint j = 1; j < MLO_FILTER_STRIDE1; ++j)
        {
            q2 += MLO_OUT_STRIDE;
#if MLO_VERT_ALIGNED == 0
            if(out_y + j < MLO_OUT_HEIGHT)
#endif
            {

                for(uint s = 0; s < MLO_READ_UNIT * MLO_FILTER_STRIDE0; ++s)
                {
#if MLO_HORIZ_ALIGNED == 0
                    if(out_x + s < MLO_OUT_WIDTH)
#endif
                    {
                        *(q2 + s) = 0;
                    }
                }
            }
        }
#endif
    }
}

/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/

#define _FLOAT float
#define _FLOAT2 float2
#define _FLOAT4 float4
#define _FLOAT8 float8

#ifndef FLT_MAX
#define FLT_MAX 3.402823466e+38F /* max value */
#endif

#define UNUSED __attribute__((__unused__))

#define DBG_OUT_OF_RNGE 0

// calculating the size of the area for weights prefetch

__attribute__((always_inline)) uint iDiv(uint v, uint d)
{
    uint r = (uint)((float)v * (1.0f / (float)d) + 0.00001f);
    return (r);
}

__attribute__((always_inline)) uint iMod(uint v, uint u, uint d)
{
    uint r = v - mul24(u, d);
    return (r);
}

__attribute__((reqd_work_group_size(MLO_GRP_SZ0, MLO_GRP_SZ1, MLO_GRP_SZ2))) __kernel void
MIOpenConv1x1(const __global _FLOAT* __restrict in_ptr,
              __constant _FLOAT* __restrict wei_ptr,
#if MLO_CONV_BIAS
              const __global _FLOAT* __restrict bias,
#endif
              __global _FLOAT* __restrict out_ptr,
              UNUSED _FLOAT dummy_val // nothing
              )
{

    _FLOAT weights[MLO_N_LCL_OUT_MAPS][MLO_N_LCL_IN_MAPS];

    uint gbl_id0  = get_global_id(0);
    uint batch_id = gbl_id0 / MLO_MAP_SZ4; // batch
    uint pos      = gbl_id0 % MLO_MAP_SZ4;

    uint out_grp_block = get_group_id(1); // block of outputs for the entire group
    uint out_id        = out_grp_block * MLO_N_LCL_OUT_MAPS;

    uint gbl_in_off = batch_id * MLO_IN_BATCH_STRIDE + pos * MLO_READ_UNIT;

    uint wei_off = out_id *
#if MLO_DIR_FORWARD == 1
                   MLO_WEI_BSTRIDE
#else
                   MLO_WEI_CHANNEL_STRIDE
#endif
        ;

    _FLOAT accum[MLO_N_LCL_OUT_MAPS][MLO_READ_UNIT];
    _FLOAT dat[MLO_N_LCL_IN_MAPS][MLO_READ_UNIT];

    for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            accum[o][i] = 0;
        }
    }

    for(uint ci = 0; ci < MLO_CLOOP0; ++ci,
             // move input offset
                                      gbl_in_off += MLO_N_LCL_IN_MAPS * MLO_IN_CHANNEL_STRIDE,

             // move weights offset
                                      wei_off += MLO_N_LCL_IN_MAPS *
#if MLO_DIR_FORWARD == 1
                                                 MLO_WEI_CHANNEL_STRIDE
#else
                                                 MLO_WEI_BSTRIDE
#endif
        )
    {
        // read weights

        __constant _FLOAT* w1 = wei_ptr + wei_off;

        for(uint o = 0, o < MLO_N_LCL_OUT_MAPS; ++o,
                 w1 +=
#if MLO_DIR_FORWARD == 1
                                                MLO_WEI_BSTRIDE
#else
                                                MLO_WEI_CHANNEL_STRIDE
#endif
            )
        {
            __constant _FLOAT* w2 = w1;
            for(uint c = 0 c < MLO_N_LCL_IN_MAPS; ++c,
                     w2 +=
#if MLO_DIR_FORWARD == 1
                                                  MLO_WEI_CHANNEL_STRIDE
#else
                                                  MLO_WEI_BSTRIDE
#endif
                )
            {
                weights[o][c] = *w2;
#if DBG_OUT_OF_RNGE
                if(wei_off2 >= MLO_N_INPUTS * MLO_N_OUTPUTS)
                {
                    printf("K:oor: weights\n");
                }
#endif
            }
        }

        // convolve with all weights
        // read data
        // Shader compiler will use      GLOAL_LOAD_DWORD's OFFSET for *(ptr+index) access
        // Shader compiler will not use  GLOAL_LOAD_DWORD's OFFSET for ptr[index] access

        __global const float* p = in_ptr + gbl_in_off;

        for(uint j = 0; j < MLO_N_LCL_IN_MAPS; j++)
        {
            for(uint i = 0; i < MLO_READ_UNIT; ++i)
            {
                dat[j][i] = *(p + i);
#if DBG_OUT_OF_RNGE
                if(gbl_in_off1 + i >= MLO_IN_BATCH_STRIDE * MLO_BATCH_SZ)
                {
                    printf("K:oor: inputs\n");
                }
#endif
            }
            p += MLO_IN_CHANNEL_STRIDE;
        }

        // convolve
        for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
        {
            for(uint c = 0; c < MLO_N_LCL_IN_MAPS; ++c)
            {
                for(uint i = 0; i < MLO_READ_UNIT; ++i)
                {
                    accum[o][i] += dat[c][i] * weights[o][c];
                }
            }
        }
    }

    uint gbl_out_off =
        batch_id * MLO_OUT_BATCH_STRIDE + pos * MLO_READ_UNIT + out_id * MLO_OUT_CHANNEL_STRIDE;
    _global _FLOAT* q = out_ptr + gbl_out_off;

    for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o, q += MLO_OUT_CHANNEL_STRIDE)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            *(q + i) = accum[o][i];
        }
    }
}

/************************************************************************
stride and padding
*************************************************************************/
__attribute__((reqd_work_group_size(MLO_GRP_SZ0, MLO_GRP_SZ1, MLO_GRP_SZ2))) __kernel void
MIOpenConv1x1pquv(const __global _FLOAT* __restrict in_ptr,
                  __constant _FLOAT* __restrict wei_ptr,
#if MLO_CONV_BIAS
                  const __global _FLOAT* __restrict bias,
#endif
                  __global _FLOAT* __restrict out_ptr,
                  UNUSED _FLOAT dummy_val // nothing
                  )
{

    _FLOAT weights[MLO_N_LCL_OUT_MAPS][MLO_N_LCL_IN_MAPS];

    uint gbl_id0 = get_global_id(0);

    uint batch_id  = gbl_id0 / MLO_MAP_SZ4; // batch
    uint pos       = gbl_id0 % MLO_MAP_SZ4;
    uint pos_out_y = pos / MLO_OUT_WIDTH4;
    uint pos_out_x = pos % MLO_OUT_WIDTH4;

#if MLO_DIR_FORWARD == 1
    uint pos_in_y = pos_out_y * MLO_FILTER_STRIDE1;
    uint pos_in_x = pos_out_x * MLO_FILTER_STRIDE0;
#else
    uint pos_in_y = pos_out_y; /// MLO_FILTER_STRIDE1;   - divided already
    uint pos_in_x = pos_out_x; // MLO_FILTER_STRIDE0;  - divided already
#endif

    uint out_grp_block = get_group_id(1); // block of outputs for the entire group
    uint out_id        = out_grp_block * MLO_N_LCL_OUT_MAPS;

    uint gbl_in_off =
        batch_id * MLO_IN_BATCH_STRIDE + pos_in_y * MLO_IN_STRIDE + pos_in_x * MLO_READ_UNIT;
    //	bool vis = (pos_in_y < MLO_IN_HEIGHT);
    //	gbl_in_off = (vis) ? gbl_in_off : 0;

    uint wei_off = out_id *
#if MLO_DIR_FORWARD == 1
                   MLO_WEI_BSTRIDE
#else
                   MLO_WEI_CHANNEL_STRIDE
#endif
        ;

    _FLOAT accum[MLO_N_LCL_OUT_MAPS][MLO_READ_UNIT];
    _FLOAT dat[MLO_N_LCL_IN_MAPS][MLO_READ_UNIT];

    for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            accum[o][i] = 0;
        }
    }

    const __global _FLOAT* i_ptr = in_ptr + gbl_in_off;
    __constant _FLOAT* w_ptr     = wei_ptr + wei_off;
    for(uint ci = 0; ci < MLO_CLOOP0; ++ci)
    {

        // convolve with all weights
        // read data

        for(uint j = 0; j < MLO_N_LCL_IN_MAPS; ++j)
        {
            uint i = 0;
#if MLO_READ_UNIT > 1
            for(; i < MLO_READ_UNIT - 1; ++i)
            {
                uint off = i
#if MLO_DIR_FORWARD == 1
                           * MLO_FILTER_STRIDE0
#endif
                    ;
                dat[j][i] = *(i_ptr + off);
            }
#endif

            for(; i < MLO_READ_UNIT; ++i)
            {
                //				vis &= (pos_in_x + i*MLO_FILTER_STRIDE0 <
                // MLO_IN_WIDTH);
                uint off = i
#if MLO_DIR_FORWARD == 1
                           * MLO_FILTER_STRIDE0
#endif
                    ;
                //				off = (vis) ? off : 0;
                _FLOAT val = *(i_ptr + off);
                dat[j][i]  = val;
                //              dat[j][i] = (vis)? dat[j][i] : 0;
            }

            i_ptr += MLO_IN_CHANNEL_STRIDE;
        }
        // read weights
        __constant _FLOAT* w_ptr0 = w_ptr;

        for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
        {

            __constant _FLOAT* w_ptr1 = w_ptr0;

            for(uint c = 0; c < MLO_N_LCL_IN_MAPS; ++c)
            {
                weights[o][c] = *w_ptr1;
                w_ptr1 +=
#if MLO_DIR_FORWARD == 1
                    MLO_WEI_CHANNEL_STRIDE
#else
                    MLO_WEI_BSTRIDE
#endif
                    ;
            }

            w_ptr0 +=
#if MLO_DIR_FORWARD == 1
                MLO_WEI_BSTRIDE
#else
                MLO_WEI_CHANNEL_STRIDE
#endif
                ;
        }

        w_ptr += MLO_N_LCL_IN_MAPS *
#if MLO_DIR_FORWARD == 1
                 MLO_WEI_CHANNEL_STRIDE
#else
                 MLO_WEI_BSTRIDE
#endif
            ;
        // convolve
        for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
        {
            for(uint c = 0; c < MLO_N_LCL_IN_MAPS; ++c)
            {
                for(uint i = 0; i < MLO_READ_UNIT; ++i)
                {
                    accum[o][i] += dat[c][i] * weights[o][c];
#if 0
				if (pos_out_y == 2 && pos_out_x == 0)
				{
					printf((__constant char *)"K:c: %f %f %f %f\n",
					accum[o][i],
					dat[c][i] * weights[o][c],
					dat[c][i],
					weights[o][c]
					);
				}
#endif
                }
            }
        }
    }

    uint out_y = pos_out_y
#if MLO_DIR_FORWARD == 0
                 * MLO_FILTER_STRIDE1
#endif
        ;
    uint out_x = pos_out_x
#if MLO_DIR_FORWARD == 0
                 * MLO_FILTER_STRIDE0
#endif
        ;

    uint gbl_out_off = batch_id * MLO_OUT_BATCH_STRIDE + out_id * MLO_OUT_CHANNEL_STRIDE +
                       out_y * MLO_OUT_STRIDE + out_x * MLO_READ_UNIT;

    _global _FLOAT* q = out_ptr + gbl_out_off;

    for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o, q += MLO_OUT_CHANNEL_STRIDE)
    {

        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            _global _FLOAT* q1 = q;
            q1 += i
#if MLO_DIR_FORWARD == 0

                  * MLO_FILTER_STRIDE0;
#endif
            ;
            *q1 = accum[o][i];

#if MLO_DIR_FORWARD == 0
            for(uint s = 1; s < MLO_FILTER_STRIDE0; ++s)
            {
#if MLO_HORIZ_ALIGNED == 0
                if(out_x + s < MLO_OUT_WIDTH)
#endif
                {
                    *(q1 + s) = 0;
                }
            }
#endif
        }

#if MLO_DIR_FORWARD == 0
        _global _FLOAT* q2 = q;
        for(uint j = 1; j < MLO_FILTER_STRIDE1; ++j)
        {
            q2 += MLO_OUT_STRIDE;
#if MLO_VERT_ALIGNED == 0
            if(out_y + j < MLO_OUT_HEIGHT)
#endif
            {

                for(uint s = 0; s < MLO_READ_UNIT * MLO_FILTER_STRIDE0; ++s)
                {
#if MLO_HORIZ_ALIGNED == 0
                    if(out_x + s < MLO_OUT_WIDTH)
#endif
                    {
                        *(q2 + s) = 0;
                    }
                }
            }
        }
#endif
    }
}