#ifndef VIENNACL_LINALG_KERNELS_SVD_SOURCE_HPP_
#define VIENNACL_LINALG_KERNELS_SVD_SOURCE_HPP_
//Automatically generated file from auxiliary-directory, do not edit manually!
/** @file svd_source.h
 *  @brief OpenCL kernel source file, generated automatically. */
namespace viennacl
{
 namespace linalg
 {
  namespace kernels
  {
const char * const svd_align1_transpose_inplace = 
"__kernel void transpose_inplace(__global float* input,\n"
"                        unsigned int row_num,\n"
"                        unsigned int col_num) {\n"
"    unsigned int size = row_num * col_num;\n"
"    for(unsigned int i = get_global_id(0); i < size; i+= get_global_size(0)) {\n"
"        unsigned int row = i / col_num;\n"
"        unsigned int col = i - row*col_num;\n"
"        unsigned int new_pos = col * row_num + row;\n"
"        //new_pos = (col < row) ? 0 : 1;\n"
"        //input[i] = new_pos;\n"
"        if(i < new_pos) {\n"
"            float val = input[i];\n"
"            input[i] = input[new_pos];\n"
"            input[new_pos] = val;\n"
"        }\n"
"    }\n"
"}\n"
; //svd_align1_transpose_inplace

const char * const svd_align1_house_update_A_left = 
"void col_reduce_lcl_array(__local float* sums, uint lcl_id, uint lcl_sz);\n"
"__kernel void house_update_A_left(\n"
"                        __global float* A,\n"
"                        __constant float* V, //householder vector\n"
"                        uint row_start,\n"
"                        uint col_start,\n"
"                        uint size1,\n"
"                        uint size2,\n"
"                        uint stride,\n"
"                        __local float* sums\n"
"                        ) {\n"
"    uint glb_id = get_global_id(0);\n"
"    uint glb_sz = get_global_size(0);\n"
"    uint grp_id = get_group_id(0);\n"
"    uint grp_nm = get_num_groups(0);\n"
"    uint lcl_id = get_local_id(0);\n"
"    uint lcl_sz = get_local_size(0);\n"
"    float ss = 0;\n"
"    // doing it in slightly different way to avoid cache misses\n"
"    for(uint i = glb_id + col_start; i < size2; i += glb_sz) {\n"
"        ss = 0;\n"
"        for(uint j = row_start; j < size1; j++) ss = ss + (V[j] * A[j * stride + i]);\n"
"        for(uint j = row_start; j < size1; j++)\n"
"            A[j * stride + i] = A[j * stride + i] - (2 * V[j] * ss);\n"
"    }\n"
"}\n"
; //svd_align1_house_update_A_left

const char * const svd_align1_copy_col = 
"// probably, this is a ugly way\n"
"__kernel void copy_col(__global float* A,\n"
"                       __global float* V,\n"
"                       uint row_start,\n"
"                       uint col_start,\n"
"                       uint size,\n"
"                       uint stride\n"
"                       ) {\n"
"    uint glb_id = get_global_id(0);\n"
"    uint glb_sz = get_global_size(0);\n"
"    for(uint i = row_start + glb_id; i < size; i += glb_sz) {\n"
"        V[i - row_start] = A[i * stride + col_start];\n"
"    }    \n"
"}\n"
; //svd_align1_copy_col

const char * const svd_align1_final_iter_update = 
"__kernel void final_iter_update(__global float* A,\n"
"                                uint stride,\n"
"                                uint n,\n"
"                                uint last_n,\n"
"                                float q,\n"
"                                float p\n"
"                                )\n"
"{\n"
"    uint glb_id = get_global_id(0);\n"
"    uint glb_sz = get_global_size(0);\n"
"    for (uint px = glb_id; px < last_n; px += glb_sz)\n"
"    {\n"
"        float v_in = A[n * stride + px];\n"
"        float z = A[(n - 1) * stride + px];\n"
"        A[(n - 1) * stride + px] = q * z + p * v_in;\n"
"        A[n * stride + px] = q * v_in - p * z;\n"
"    }\n"
"}\n"
; //svd_align1_final_iter_update

const char * const svd_align1_house_update_A_right = 
"void col_reduce_lcl_array(__local float* sums, uint lcl_id, uint lcl_sz);\n"
"__kernel void house_update_A_right(\n"
"                        __global float* A,\n"
"                        __global float* V, // householder vector\n"
"                        uint row_start,\n"
"                        uint col_start,\n"
"                        uint size1,\n"
"                        uint size2,\n"
"                        uint stride,\n"
"                        __local float* sums\n"
"                        ) {\n"
"    uint glb_id = get_global_id(0);\n"
"    uint grp_id = get_group_id(0);\n"
"    uint grp_nm = get_num_groups(0);\n"
"    uint lcl_id = get_local_id(0);\n"
"    uint lcl_sz = get_local_size(0);\n"
"    float ss = 0;\n"
"    // update of A matrix\n"
"    for(uint i = grp_id + row_start; i < size1; i += grp_nm) {\n"
"        ss = 0;\n"
"        for(uint j = lcl_id; j < size2; j += lcl_sz) ss = ss + (V[j] * A[i * stride + j]);\n"
"        sums[lcl_id] = ss;\n"
"        barrier(CLK_LOCAL_MEM_FENCE);\n"
"        col_reduce_lcl_array(sums, lcl_id, lcl_sz);\n"
"        barrier(CLK_LOCAL_MEM_FENCE);\n"
"        float sum_Av = sums[0];\n"
"        for(uint j = lcl_id; j < size2; j += lcl_sz)\n"
"            A[i * stride + j] = A[i * stride + j] - (2 * V[j] * sum_Av);\n"
"    }\n"
"}\n"
; //svd_align1_house_update_A_right

const char * const svd_align1_bidiag_pack = 
"__kernel void bidiag_pack(__global float* A,\n"
"                          __global float* D,\n"
"                          __global float* S,\n"
"                          uint size1,\n"
"                          uint size2,\n"
"                          uint stride\n"
"                          ) {\n"
"    uint size = min(size1, size2);\n"
"    if(get_global_id(0) == 0)\n"
"        S[0] = 0;\n"
"    for(uint i = get_global_id(0); i < size ; i += get_global_size(0)) {\n"
"        D[i] = A[i*stride + i];\n"
"        S[i + 1] = (i + 1 < size2) ? A[i*stride + (i + 1)] : 0;\n"
"    }\n"
"}\n"
; //svd_align1_bidiag_pack

const char * const svd_align1_col_reduce_lcl_array = 
"// calculates a sum of local array elements\n"
"void col_reduce_lcl_array(__local float* sums, uint lcl_id, uint lcl_sz) {\n"
"    uint step = lcl_sz >> 1;\n"
"    while(step > 0) {\n"
"        if(lcl_id < step) {\n"
"            sums[lcl_id] += sums[lcl_id + step];\n"
"        }\n"
"        step >>= 1;\n"
"        barrier(CLK_LOCAL_MEM_FENCE);\n"
"    }\n"
"}\n"
; //svd_align1_col_reduce_lcl_array

const char * const svd_align1_inverse_signs = 
"__kernel void inverse_signs(__global float* v,\n"
"                            __global float* signs,\n"
"                            uint size,\n"
"                            uint stride \n"
"                            )\n"
"{\n"
"    uint glb_id_x = get_global_id(0);\n"
"    uint glb_id_y = get_global_id(1);\n"
"    if((glb_id_x < size) && (glb_id_y < size))\n"
"        v[glb_id_x * stride + glb_id_y] *= signs[glb_id_x];\n"
"}\n"
; //svd_align1_inverse_signs

const char * const svd_align1_update_qr_column = 
"__kernel void update_qr_column(__global float* A,\n"
"                               uint stride,\n"
"                               __global float* buf,\n"
"                               int m,\n"
"                               int n,\n"
"                               int last_n\n"
"                              )\n"
"{\n"
"    uint glb_id = get_global_id(0);\n"
"    uint glb_sz = get_global_size(0);\n"
"    for (int i = glb_id; i < last_n; i += glb_sz)\n"
"    {\n"
"        float a_ik = A[m * stride + i], a_ik_1, a_ik_2;\n"
"        a_ik_1 = A[(m + 1) * stride + i];\n"
"        for(int k = m; k < n; k++)\n"
"        {\n"
"            bool notlast = (k != n - 1);\n"
"            float p = buf[5 * k] * a_ik + buf[5 * k + 1] * a_ik_1;\n"
"            \n"
"            if (notlast)\n"
"            {\n"
"                a_ik_2 = A[(k + 2) * stride + i];\n"
"                p = p + buf[5 * k + 2] * a_ik_2;\n"
"                a_ik_2 = a_ik_2 - p * buf[5 * k + 4];\n"
"            }\n"
"            A[k * stride + i] = a_ik - p;\n"
"            a_ik_1 = a_ik_1 - p * buf[5 * k + 3];\n"
"            \n"
"            a_ik = a_ik_1;\n"
"            a_ik_1 = a_ik_2;\n"
"        }\n"
"        A[n * stride + i] = a_ik;\n"
"    }\n"
"}\n"
; //svd_align1_update_qr_column

const char * const svd_align1_house_update_QL = 
"void col_reduce_lcl_array(__local float* sums, uint lcl_id, uint lcl_sz);\n"
"__kernel void house_update_QL(\n"
"                        __global float* QL,\n"
"                        __constant float* V, //householder vector\n"
"                        uint size1,\n"
"                        uint size2,\n"
"                        uint strideQ,\n"
"                        __local float* sums\n"
"                        ) {\n"
"    uint glb_id = get_global_id(0);\n"
"    uint glb_sz = get_global_size(0);\n"
"    uint grp_id = get_group_id(0);\n"
"    uint grp_nm = get_num_groups(0);\n"
"    uint lcl_id = get_local_id(0);\n"
"    uint lcl_sz = get_local_size(0);\n"
"    float ss = 0;\n"
"    // update of left matrix\n"
"    for(uint i = grp_id; i < size1; i += grp_nm) {\n"
"        ss = 0;\n"
"        for(uint j = lcl_id; j < size1; j += lcl_sz) ss = ss + (V[j] * QL[i * strideQ + j]);\n"
"        sums[lcl_id] = ss;\n"
"        barrier(CLK_LOCAL_MEM_FENCE);\n"
"        col_reduce_lcl_array(sums, lcl_id, lcl_sz);\n"
"        barrier(CLK_LOCAL_MEM_FENCE);\n"
"        float sum_Qv = sums[0];\n"
"        for(uint j = lcl_id; j < size1; j += lcl_sz)\n"
"            QL[i * strideQ + j] = QL[i * strideQ + j] - (2 * V[j] * sum_Qv);\n"
"    }\n"
"}\n"
; //svd_align1_house_update_QL

const char * const svd_align1_copy_row = 
"// probably, this is too\n"
"__kernel void copy_row(__global float* A,\n"
"                       __global float* V,\n"
"                       uint row_start,\n"
"                       uint col_start,\n"
"                       uint size,\n"
"                       uint stride\n"
"                       ) {\n"
"    uint glb_id = get_global_id(0);\n"
"    uint glb_sz = get_global_size(0);\n"
"    for(uint i = col_start + glb_id; i < size; i += glb_sz) {\n"
"        V[i - col_start] = A[row_start * stride + i];\n"
"    }\n"
"}\n"
; //svd_align1_copy_row

const char * const svd_align1_givens_prev = 
"__kernel void givens_prev(__global float* matr,\n"
"                            __global float* cs,\n"
"                            __global float* ss,\n"
"                            uint size,\n"
"                            uint stride,\n"
"                            uint start_i,\n"
"                            uint end_i\n"
"                            )\n"
"{\n"
"    uint glb_id = get_global_id(0);\n"
"    uint glb_sz = get_global_size(0);\n"
"    uint lcl_id = get_local_id(0);\n"
"    uint lcl_sz = get_local_size(0);\n"
"    uint j = glb_id;\n"
"    __local float cs_lcl[256];\n"
"    __local float ss_lcl[256];\n"
"    float x = (j < size) ? matr[(start_i - 1) * stride + j] : 0;\n"
"    uint elems_num = end_i - start_i;\n"
"    uint block_num = (elems_num + lcl_sz - 1) / lcl_sz;\n"
"    for(uint block_id = 0; block_id < block_num; block_id++)\n"
"    {\n"
"        uint to = min(elems_num - block_id * lcl_sz, lcl_sz);\n"
"        if(lcl_id < to)\n"
"        {\n"
"            cs_lcl[lcl_id] = cs[lcl_id + start_i + block_id * lcl_sz];\n"
"            ss_lcl[lcl_id] = ss[lcl_id + start_i + block_id * lcl_sz];\n"
"        }\n"
"        barrier(CLK_LOCAL_MEM_FENCE);\n"
"        if(j < size)\n"
"        {\n"
"            for(uint ind = 0; ind < to; ind++)\n"
"            {\n"
"                uint i = ind + start_i + block_id * lcl_sz;\n"
"                float z = matr[i * stride + j];\n"
"                float cs_val = cs_lcl[ind];//cs[i];\n"
"                float ss_val = ss_lcl[ind];//ss[i];\n"
"                matr[(i - 1) * stride + j] = x * cs_val + z * ss_val;\n"
"                x = -x * ss_val + z * cs_val;\n"
"            }\n"
"        }\n"
"        barrier(CLK_LOCAL_MEM_FENCE);\n"
"    }\n"
"    if(j < size)\n"
"        matr[(end_i - 1) * stride + j] = x;\n"
"}\n"
; //svd_align1_givens_prev

const char * const svd_align1_givens_next = 
"__kernel void givens_next(__global float* matr,\n"
"                            __global float* cs,\n"
"                            __global float* ss,\n"
"                            uint size,\n"
"                            uint stride,\n"
"                            uint start_i,\n"
"                            uint end_i\n"
"                            )\n"
"{\n"
"    uint glb_id = get_global_id(0);\n"
"    uint glb_sz = get_global_size(0);\n"
"    uint lcl_id = get_local_id(0);\n"
"    uint lcl_sz = get_local_size(0);\n"
"    uint j = glb_id;\n"
"    __local float cs_lcl[256];\n"
"    __local float ss_lcl[256];\n"
"    float x = (j < size) ? matr[(end_i + 1) * stride + j] : 0;\n"
"    uint elems_num = end_i - start_i + 1;\n"
"    uint block_num = (elems_num + lcl_sz - 1) / lcl_sz;\n"
"    for(uint block_id = 0; block_id < block_num; block_id++)\n"
"    {\n"
"        uint to = min(elems_num - block_id * lcl_sz, lcl_sz);\n"
"        if(lcl_id < to)\n"
"        {\n"
"            cs_lcl[lcl_id] = cs[end_i - (lcl_id + block_id * lcl_sz)];\n"
"            ss_lcl[lcl_id] = ss[end_i - (lcl_id + block_id * lcl_sz)];;\n"
"        }\n"
"        barrier(CLK_LOCAL_MEM_FENCE);\n"
"        if(j < size)\n"
"        {\n"
"            for(uint ind = 0; ind < to; ind++)\n"
"            {\n"
"                uint i = end_i - (ind + block_id * lcl_sz);\n"
"                float z = matr[i * stride + j];\n"
"                float cs_val = cs_lcl[ind];\n"
"                float ss_val = ss_lcl[ind];\n"
"                matr[(i + 1) * stride + j] = x * cs_val + z * ss_val;\n"
"                x = -x * ss_val + z * cs_val;\n"
"            }\n"
"        }\n"
"        barrier(CLK_LOCAL_MEM_FENCE);\n"
"    }\n"
"    if(j < size)\n"
"        matr[(start_i) * stride + j] = x;\n"
"}\n"
; //svd_align1_givens_next

const char * const svd_align1_house_update_QR = 
"void col_reduce_lcl_array(__local float* sums, uint lcl_id, uint lcl_sz);\n"
"__kernel void house_update_QR(\n"
"                        __global float* QR,\n"
"                        __global float* V, // householder vector\n"
"                        uint size1,\n"
"                        uint size2,\n"
"                        uint strideQ,\n"
"                        __local float* sums\n"
"                        ) {\n"
"    uint glb_id = get_global_id(0);\n"
"    uint grp_id = get_group_id(0);\n"
"    uint grp_nm = get_num_groups(0);\n"
"    uint lcl_id = get_local_id(0);\n"
"    uint lcl_sz = get_local_size(0);\n"
"    float ss = 0;\n"
"    // update of QR matrix\n"
"    // Actually, we are calculating a transpose of right matrix. This allows to avoid cache\n"
"    // misses. \n"
"    for(uint i = grp_id; i < size2; i += grp_nm) {\n"
"        ss = 0;\n"
"        for(uint j = lcl_id; j < size2; j += lcl_sz) ss = ss + (V[j] * QR[i * strideQ + j]);\n"
"        sums[lcl_id] = ss;\n"
"        barrier(CLK_LOCAL_MEM_FENCE);\n"
"        col_reduce_lcl_array(sums, lcl_id, lcl_sz);\n"
"        barrier(CLK_LOCAL_MEM_FENCE);\n"
"        float sum_Qv = sums[0];\n"
"        for(uint j = lcl_id; j < size2; j += lcl_sz)\n"
"            QR[i * strideQ + j] = QR[i * strideQ + j] - (2 * V[j] * sum_Qv);\n"
"    }\n"
"}\n"
; //svd_align1_house_update_QR

  }  //namespace kernels
 }  //namespace linalg
}  //namespace viennacl
#endif

