#include <stdio.h>
#include <cuda_runtime_api.h>
#include <cuComplex.h>
#include <cuda_fp16.h>

#include "gpu_LocalizeMUSIC.h"
#include "gpu_common.h"

//#define MULTI_GPU

//add normalize corr
cuComplex *tmp_xx;
cuComplex *d_X;

cuComplex *d_Rxx;
cuComplex *d_R;
int *d_UsesFreq;
float *b, *z;
float *d_EigenValue;
cuComplex *d_E;
cuComplex *d_A;
float *d_MSSW;
float *d_Pavg;
float *d_Pavg_sum;

//temp
cuComplex *tmp_Rxx;
float *tmp_Pavg;

int g_lower;
int g_upper;

float ***Pavg_sum2;

//svd
float *d_bb; 
float *d_cc; 
float *d_tt; 
//float *d_ss; 
float *d_eps; 
cuComplex *d_TempCalc4;
cuComplex *d_TempCalc3;
float *d_REigenValue;

//int process_id;
//#ifdef MULTI_GPU
////0,1,2,3 -> 4,5,6,7
//int gpu_id[4]={1,2,0,3};
//#else
//int gpu_id[1]={0};
//#endif

void gpu_init(int pslength, int nb_channel, int *UsesFreq){
    //CUDA_SAFE_CALL(cudaSetDevice(0));
    printf("process_id = %d\n", process_id);
    //printf("gpu_id[%d] = %d\n", process_id, gpu_id[process_id]);

    //gpu_set_device(process_id, gpu_id[process_id]);
    gpu_set_device(process_id);

    //CUDA_SAFE_CALL(cudaSetDevice(gpu_id[process_id]));
    //CUDA_SAFE_CALL(cudaSetDevice(process_id));

    //CUDA_SAFE_CALL(cudaProfilerStart());

    //dummy
    cudaFree(NULL);

    CUDA_SAFE_CALL(cudaMalloc((void **)&d_Rxx, sizeof(cuComplex)*pslength*nb_channel*nb_channel));
    CUDA_SAFE_CALL(cudaMalloc((void **)&d_R, sizeof(cuComplex)*pslength*nb_channel*nb_channel));
    //CUDA_SAFE_CALL(cudaMalloc((void **)&b, sizeof(float)*16*pslength));
    //CUDA_SAFE_CALL(cudaMalloc((void **)&z, sizeof(float)*16*pslength));
    CUDA_SAFE_CALL(cudaMalloc((void **)&b, sizeof(float)*MAX_CH_NUM*pslength));
    CUDA_SAFE_CALL(cudaMalloc((void **)&z, sizeof(float)*MAX_CH_NUM*pslength));

    CUDA_SAFE_CALL(cudaMalloc((void **)&d_EigenValue, sizeof(float)*pslength*nb_channel));
    CUDA_SAFE_CALL(cudaMalloc((void **)&d_E, sizeof(cuComplex)*pslength*nb_channel*nb_channel));

    CUDA_SAFE_CALL(cudaMalloc((void **)&d_UsesFreq, sizeof(int)*pslength));

    CUDA_SAFE_CALL(cudaMemcpy(d_UsesFreq, UsesFreq, sizeof(int)*pslength, cudaMemcpyHostToDevice));

    //temp
    //tmp_Rxx = (cuComplex *)malloc(sizeof(cuComplex)*pslength*nb_channel*nb_channel);
    CUDA_SAFE_CALL(cudaMallocHost((void **)&tmp_Rxx, sizeof(cuComplex)*pslength*nb_channel*nb_channel));

    //svd temp
    CUDA_SAFE_CALL(cudaMalloc((void **)&d_bb, sizeof(float)*MAX_CH_NUM*pslength));
    CUDA_SAFE_CALL(cudaMalloc((void **)&d_cc, sizeof(float)*MAX_CH_NUM*pslength));
    CUDA_SAFE_CALL(cudaMalloc((void **)&d_tt, sizeof(float)*MAX_CH_NUM*pslength));
    //CUDA_SAFE_CALL(cudaMalloc((void **)&d_ss, sizeof(float)*MAX_CH_NUM*pslength));
    CUDA_SAFE_CALL(cudaMalloc((void **)&d_eps, sizeof(float)*pslength));
    CUDA_SAFE_CALL(cudaMalloc((void **)&d_TempCalc4, sizeof(cuComplex)*nb_channel*nb_channel*pslength));
    CUDA_SAFE_CALL(cudaMalloc((void **)&d_TempCalc3, sizeof(cuComplex)*nb_channel*nb_channel*pslength));
    CUDA_SAFE_CALL(cudaMalloc((void **)&d_REigenValue, sizeof(float)*MAX_CH_NUM*pslength));

    CUDA_SAFE_CALL(cudaDeviceSynchronize());
}

void gpu_init2(int pslength, int nb_channel, int height_num, int direction_num, int range_num,
    //COMPLEX_FLOAT ****AMatrix, float *MSSW){
    COMPLEX_FLOAT *****AMatrix, float *MSSW,
    int window, int look_back, int look_ahead
    )
{
    printf("--------- window=%d\n", window);
    printf("--------- look_back=%d\n", look_back);
    printf("--------- look_ahead=%d\n", look_ahead);

    //tmp
    tmp_xx = (cuComplex *)malloc(sizeof(cuComplex)*nb_channel*pslength*window);

    CUDA_SAFE_CALL(cudaMalloc((void **)&d_X, sizeof(cuComplex)*nb_channel*pslength*window));

    //CUDA_SAFE_CALL(cudaMalloc((void **)&d_A, sizeof(cuComplex)*direction_num*range_num*pslength*nb_channel));
    CUDA_SAFE_CALL(cudaMalloc((void **)&d_A, sizeof(cuComplex)*height_num*direction_num*range_num*pslength*nb_channel));

    //A  
    cuComplex *tmp_A;
    tmp_A = (cuComplex *)malloc(sizeof(cuComplex)*height_num*direction_num*range_num*pslength*nb_channel);

    int ih,id,ir,il,ic,idx;
    for(ih=0; ih<height_num; ih++){
        for(id=0; id<direction_num; id++){
            for(ir=0; ir<range_num; ir++){
                for(il=0; il<pslength; il++){
                    for(ic=0; ic<nb_channel; ic++){
                        //idx=id*range_num*pslength*nb_channel + ir*pslength*nb_channel + il*nb_channel + ic;
                        //tmp_A[idx].x = A[id][ir][il][ic].real;
                        //tmp_A[idx].y = A[id][ir][il][ic].imag;
                        idx=ih*direction_num*range_num*pslength*nb_channel + id*range_num*pslength*nb_channel + ir*pslength*nb_channel + il*nb_channel + ic;
                        tmp_A[idx].x = AMatrix[ih][id][ir][il][ic].real;
                        tmp_A[idx].y = AMatrix[ih][id][ir][il][ic].imag;
                    }
                }
            }
        }
    }
    CUDA_SAFE_CALL(cudaMemcpy(d_A, tmp_A, sizeof(cuComplex)*height_num*direction_num*range_num*pslength*nb_channel, cudaMemcpyHostToDevice));

    //MSSW
    CUDA_SAFE_CALL(cudaMalloc((void **)&d_MSSW, sizeof(float)*(512+1)));
    CUDA_SAFE_CALL(cudaMemcpy(d_MSSW, MSSW, sizeof(float)*(512+1), cudaMemcpyHostToDevice));

    //Pavg
    //CUDA_SAFE_CALL(cudaMalloc((void **)&d_Pavg, sizeof(float)*direction_num*range_num));
    CUDA_SAFE_CALL(cudaMalloc((void **)&d_Pavg, sizeof(float)*height_num*direction_num*range_num));

    //Pavg_sum
    CUDA_SAFE_CALL(cudaMalloc((void **)&d_Pavg_sum, sizeof(float)*direction_num));

    //tmp_Pavg = (float *)malloc(sizeof(float)*direction_num*range_num);
    //CUDA_SAFE_CALL(cudaMallocHost((void **)&tmp_Pavg, sizeof(float)*direction_num*range_num));
    CUDA_SAFE_CALL(cudaMallocHost((void **)&tmp_Pavg, sizeof(float)*height_num*direction_num*range_num));

    free(tmp_A);

    //Pavg_sum2 = (float ***)MemoryAllocate3D(height_num, direction_num, range_num, sizeof(float));
    Pavg_sum2 = (float ***)malloc(sizeof(float **) * height_num);
    for(ih=0; ih<height_num; ih++){
        Pavg_sum2[ih] = (float **)malloc(sizeof(float *) * direction_num);
        for(id=0; id<direction_num; id++){
            Pavg_sum2[ih][id] = (float *)malloc(sizeof(float) * range_num);
        }
    }

    CUDA_SAFE_CALL(cudaDeviceSynchronize());
}

__global__
void _gpu_AddCorrelation(cuComplex *X, cuComplex *Rxx,
    int win_num,
    int pslength, int nb_channel, int st_freq)
{
    int i,j,k;
    float tmp;
    //COMPLEX_FLOAT x_i,x_j;
    cuComplex x_i, x_j;
    
    int w;
    //dim3 grid(win_size, calc_freq);
    w = blockIdx.x;
    k = blockIdx.y + st_freq;
    j = threadIdx.x;
    i = threadIdx.y;

    if((k>=pslength) || (j>=nb_channel) || (i>=nb_channel)){
        return;
    }

    //for(k=0; k<pslength; k++){
        //if(UsesFreq[k]){
            //for(j=0; j<nb_channel; j++){
                //for(i=0; i<nb_channel; i++){
            //for(i=0; i<nb_channel; i++){
                //x_i = X[i][k];
                //x_i = X[i*pslength + k];
                x_i = X[w*nb_channel*pslength + i*pslength + k];
                //for(j=0; j<nb_channel; j++){
                    // 直積（outer_prod）の計算
                    // Rxx[k][i][j] += X[i][k] * X[j][k];
                    //f_real =  X[i][k].real * X[j][k].real + X[i][k].imag * X[j][k].imag;
                    //f_imag = -X[i][k].real * X[j][k].imag + X[i][k].imag * X[j][k].real;
                    //Rxx[k][i][j].real += f_real;
                    //Rxx[k][i][j].imag += f_imag;
                    //x_j = X[j][k];
                    //x_j = X[j*pslength + k];
                    x_j = X[w*nb_channel*pslength + j*pslength + k];
                    //tmp  =  x_i.real * x_j.real;
                    //tmp +=  x_i.imag * x_j.imag;
                    tmp  =  x_i.x * x_j.x;
                    tmp +=  x_i.y * x_j.y;

                //if(blockIdx.x==0&&j==0&&i==0)printf("tmp=%f\n",tmp);

                // Atomic
                    //Rxx[k][i][j].real += tmp;
                    //Rxx[k*nb_channel*nb_channel + i*nb_channel + j].x += tmp;
                    //Rxx[k*nb_channel*nb_channel + i*nb_channel + j].x += tmp;
                    atomicAdd(&(Rxx[k*nb_channel*nb_channel + i*nb_channel + j].x), tmp);
                    //atomicAdd(&Pavg[ih*direction_num*range_num + id*range_num + ir], (float)((norm_a / sh_G[0]) * EV_Weight));

                    //tmp  = -x_i.real * x_j.imag;
                    //tmp +=  x_i.imag * x_j.real;
                    tmp  = -x_i.x * x_j.y;
                    tmp +=  x_i.y * x_j.x;

                    //if(blockIdx.x==0&&j==0&&i==0)printf("tmp=%f\n",tmp);

                    // Atomic
                    //Rxx[k][i][j].imag += tmp;
                    //Rxx[k*nb_channel*nb_channel + i*nb_channel + j].y += tmp;
                    atomicAdd(&(Rxx[k*nb_channel*nb_channel + i*nb_channel + j].y), tmp);
                //}
            //}
            //LOGI("k=%d\n", k); k=16から88
        //}
    //}
}

__global__
void _gpu_AddCorrelation2(cuComplex *X, cuComplex *Rxx,
		int win_num,
		int pslength, int nb_channel, int st_freq)
{
    int i,j,k;
    //float tmp;
    double tmp;
    //COMPLEX_FLOAT x_i,x_j;
    cuComplex x_i, x_j;
    
    int w;
    //dim3 grid(win_size, calc_freq);
    w = blockIdx.x;
    k = blockIdx.y + st_freq;
    j = threadIdx.x;
    i = threadIdx.y;

    if((k>=pslength) || (j>=nb_channel) || (i>=nb_channel)){
        return;
    }

    x_i = X[w*nb_channel*pslength + i*pslength + k];
    x_j = X[w*nb_channel*pslength + j*pslength + k];
    tmp  = ((double)x_i.x * (double)x_j.x);
    tmp += ((double)x_i.y * (double)x_j.y);

    //if(blockIdx.x==0&&j==0&&i==0)printf("tmp=%f\n",tmp);

    // Atomic
    atomicAdd(&(Rxx[k*nb_channel*nb_channel + i*nb_channel + j].x), (float)tmp);

    //tmp  = -x_i.x * x_j.y;
    //tmp +=  x_i.y * x_j.x;
    tmp  = (-1.0*(double)x_i.x * (double)x_j.y);
    tmp += ((double)x_i.y * (double)x_j.x);

    // Atomic
    atomicAdd(&(Rxx[k*nb_channel*nb_channel + i*nb_channel + j].y), (float)tmp);
}


void gpu_AddCorrelation(cuComplex *X, cuComplex *Rxx,
    int win_size, int win_num,
    int pslength, int nb_channel)
{
    int calc_freq = g_upper- g_lower;

    dim3 block(nb_channel, nb_channel);
    //dim3 grid(calc_freq, 1);
    dim3 grid(win_size, calc_freq);
    //printf("<<<(%d, %d) (%d, %d)>>>\n", grid.x, grid.y, block.x, block.y);

    //printf("win_num=%d pslength=%d\n", win_num, pslength);

    //_gpu_AddCorrelation<<<grid, block>>>(X, Rxx, win_num, pslength, nb_channel, g_lower);

    //double Ver.
    _gpu_AddCorrelation2<<<grid, block>>>(X, Rxx, win_num, pslength, nb_channel, g_lower);

}

__global__
void _gpu_NormalizeCorrelation(cuComplex *Rxx,
    int sum_count,
    int pslength, int nb_channel, int st_freq)
{
    int i,j,k;
    //float tmp;
    cuComplex tmp;
    //COMPLEX_FLOAT x_i,x_j;
    cuComplex x_i, x_j;
    
    k = blockIdx.x + st_freq;
    j = threadIdx.x;
    i = threadIdx.y;

    if((k>=pslength) || (j>=nb_channel) || (i>=nb_channel)){
            return;
    }

    float sum_count_1 = 1.0f / (float)sum_count;

    //atomicAdd(&(Rxx[k*nb_channel*nb_channel + i*nb_channel + j].x), tmp);
    //atomicAdd(&(Rxx[k*nb_channel*nb_channel + i*nb_channel + j].y), tmp);
    tmp = Rxx[k*nb_channel*nb_channel + i*nb_channel + j];
    tmp.x *= sum_count_1;
    tmp.y *= sum_count_1;
    Rxx[k*nb_channel*nb_channel + i*nb_channel + j] = tmp;
}

void gpu_NormalizeCorrelation(cuComplex *Rxx,
    int sum_count,
    int pslength, int nb_channel)
{
    int calc_freq = g_upper- g_lower;

    dim3 block(nb_channel, nb_channel);
    //dim3 grid(calc_freq, 1);
    dim3 grid(calc_freq, 1);
    //printf("<<<(%d, %d) (%d, %d)>>>\n", grid.x, grid.y, block.x, block.y);

    //printf("win_num=%d pslength=%d\n", win_num, pslength);

   _gpu_NormalizeCorrelation<<<grid, block>>>(Rxx, sum_count, pslength, nb_channel, g_lower);
}



#if 1
__global__
//void _gpu_MaxOfAbsValue(int pslength, int *UsesFreq, int nb_channel, cuComplex *Rxx, cuComplex *R)
void _gpu_MaxOfAbsValue(int pslength, int *UsesFreq, int nb_channel, cuComplex *Rxx, cuComplex *R, int st_freq)
{
    //int k = blockIdx.x;
    int k = blockIdx.x + st_freq;
    //int x = blockIdx.x * blockDim.x + threadIdx.x;
    //int y = blockIdx.y * blockDim.y + threadIdx.y;
    int x = threadIdx.x;
    int y = threadIdx.y;

    int tid = y*blockDim.x + x;
    //int laneIdx = tid % warpSize; //0~31
    //int warpIdx = tid / warpSize; //0~3
    int laneIdx = tid % warpSize; //0~31
    int warpIdx = tid / warpSize; //0~3

    cuComplex R_elm;

    //__shared__ float sh_max[4];
    __shared__ float sh_max[MAX_CH_NUM];

    if(!UsesFreq[k]){
        return;
    }

    // Rxxの正規化（周波数単位）

    float f_max;
    float f_tmp;
    f_max = 0.0;

    int i,j;
    // MaxOfAbsValue
    for(j=threadIdx.y; j<nb_channel; j+=blockDim.y){
        for(i=threadIdx.x; i<nb_channel; i+= blockDim.x){
            //f_tmp = fabsf(Rxx[k][i][j].real);
            f_tmp = fabsf(Rxx[k*nb_channel*nb_channel + nb_channel*j + i].x);
            if(f_tmp > f_max){
                f_max = f_tmp;
            }
        }
    }

    //if(k==9){
    //    printf("k=%d (%d, %d) f_max=%f\n", k, x, y, f_max);
    //}
    __syncthreads();

    for(i=nb_channel; i>0; i >>= 1){
        f_tmp = __shfl_xor(f_max, i, 32);
        //f_tmp = __shfl_xor(f_max, i, nb_channel);
        if(f_tmp > f_max){
            f_max = f_tmp;
        }
    }

    //if (laneIdx == 0){
    if(x==0){
        //sh_max[warpIdx] = f_max;
        sh_max[y] = f_max;
        //if(k==9){
        //    printf("k=%d (%d, %d) sh_max[warpIdx]=%f\n", k, x, y, f_max);
        //}
    }
    __syncthreads();

    //ブロック内のリダクション
    for(unsigned int s = blockDim.y / 2; s > 0; s >>= 1){ //s=2,1
        if(tid<s){
            if(sh_max[tid]<sh_max[tid + s]){
                sh_max[tid] = sh_max[tid + s];
            }
        }
        __syncthreads();
    }

    f_max = sh_max[0];
    //if(k==9 && threadIdx.x==0 && threadIdx.y==0)
    //printf("k=%d f_max=%f\n", k, f_max);

    f_max += 1.0f;
    for(j=threadIdx.y; j<nb_channel; j+=blockDim.y){
        for(i=threadIdx.x; i<nb_channel; i+= blockDim.x){
            R_elm = Rxx[k*nb_channel*nb_channel + nb_channel*j + i];
            R_elm.x /= f_max;
            R_elm.y /= f_max;
            R[k*nb_channel*nb_channel + nb_channel*j + i] = R_elm;
        }
    }
}
#endif

__global__
void _gpu_MaxOfAbsValue2(int pslength, int *UsesFreq, int nb_channel, cuComplex *Rxx, cuComplex *R, int st_freq)
{
    //int k = blockIdx.x;
    int k = blockIdx.x + st_freq;
    //int x = blockIdx.x * blockDim.x + threadIdx.x;
    //int y = blockIdx.y * blockDim.y + threadIdx.y;
    int x = threadIdx.x;
    int y = threadIdx.y;

    int tid = y*blockDim.x + x;
    //int laneIdx = tid % warpSize; //0~3
    //int warpIdx = tid / warpSize; //0~3
    int laneIdx = x;
    int warpIdx = y;

    cuComplex R_elm;

    //__shared__ float sh_max[4];
    __shared__ float sh_max[MAX_CH_NUM];

    //if(!UsesFreq[k]){
    //    return;
    //}

    // Rxxの正規化（周波数単位）

    float f_max;
    float f_tmp;
    f_max = 0.0f;

    int i,j;
    // MaxOfAbsValue
    //for(j=threadIdx.y; j<nb_channel; j+=blockDim.y){
    //    for(i=threadIdx.x; i<nb_channel; i+= blockDim.x){
    //        f_tmp = fabsf(Rxx[k][i][j].real);
            R_elm = Rxx[k*nb_channel*nb_channel + nb_channel*y + x];
    //        f_tmp = fabsf(Rxx[k*nb_channel*nb_channel + nb_channel*j + i].x);
            f_max = fabsf(R_elm.x);
    //        if(f_tmp>f_max){
    //            f_max = f_tmp;
    //        }
    //    }
    //}
    __syncthreads();

    for(i=nb_channel/2; i>0; i>>=1){ //2~1
        //f_tmp = __shfl_xor(f_max, i, 32);
        f_tmp = __shfl_xor(f_max, i, nb_channel);
        //if(f_tmp>f_max){
        //    f_max = f_tmp;
	//}
        f_max = f_tmp > f_max ? f_tmp : f_max;
    }

    if(laneIdx==0){
        sh_max[warpIdx] = f_max;
    }
    __syncthreads();

    //ブロック内のリダクション
    for(unsigned int s = blockDim.y / 2; s > 0; s >>= 1){ //s=2,1
        if(tid<s){
            if(sh_max[tid]<sh_max[tid + s]){
                sh_max[tid] = sh_max[tid + s];
            }
        }
        __syncthreads();
    }
    f_max = sh_max[0];

    f_max += 1.0f;
    //for(int j=threadIdx.y; j<nb_channel; j+=blockDim.y){
    //    for(int i=threadIdx.x; i<nb_channel; i+= blockDim.x){
    //        R_elm = Rxx[k*nb_channel*nb_channel + nb_channel*j + i];
            R_elm.x /= f_max;
            R_elm.y /= f_max;
    //        R[k*nb_channel*nb_channel + nb_channel*j + i] = R_elm;
            R[k*nb_channel*nb_channel + nb_channel*y + x] = R_elm;
    //    }
    //}
}

void gpu_MaxOfAbsValue(int pslength, int *UsesFreq, int nb_channel, cuComplex *Rxx, cuComplex *R)
{
    int calc_freq = g_upper- g_lower;

    dim3 block(nb_channel, nb_channel);
    //dim3 grid(pslength, 1);
    dim3 grid(calc_freq, 1);
    _gpu_MaxOfAbsValue<<<grid, block>>>(pslength, UsesFreq, nb_channel, Rxx, R, g_lower);

    //dim3 grid(calc_freq, 1);
    //nb_channel=16までを想定
    //_gpu_MaxOfAbsValue2<<<grid, block>>>(pslength, UsesFreq, nb_channel, Rxx, R, g_lower);
}

__global__
void _gpu_CalcAveragePower(const float *EigenValue,
    const cuComplex *E,
    const cuComplex *A,
    const int *UsesFreq,
    //int NumSource,
    const float *MSSW,
    const int enable_eigenvalue_weight,
    const int nb_channel,
    const int num_source,
    const int direction_num,
    const int range_num,
    const int pslength,
    float *Pavg,
    const int st_freq
    )
{
    int ir;
#if 1
    float __shared__ sh_G[2];
    float norm_a;
    float EV_Weight;
    float fval_real;
    float fval_imag;
#else
    double __shared__ sh_G[2];
    double norm_a;
    double EV_Weight;
    double fval_real;
    double fval_imag;
#endif
    const int id = blockIdx.x;
    //const int k = blockIdx.y;
    const int k = blockIdx.y + st_freq;
    const int i = threadIdx.x;
    const int m = threadIdx.y;

    int tid = m*blockDim.x + i;
    //int laneIdx = tid % warpSize; //0~31
    //int warpIdx = tid / warpSize; //0~3

    int nb_channel_1;
    nb_channel_1 = nb_channel - 1;

    //if(!UsesFreq[k]){
    //    return;
    //}

    EV_Weight = MSSW[k]*(enable_eigenvalue_weight ? sqrt(EigenValue[k*nb_channel + nb_channel_1]) : 1.0f);

    for(ir=0; ir<range_num; ir++){  //max=4??
        fval_real = 0.0f;
        fval_imag = 0.0f;

        cuComplex a_tmp = A[id*range_num*pslength*nb_channel + ir*pslength*nb_channel + k*nb_channel + i];
        cuComplex e_tmp = E[k*nb_channel*nb_channel + i*nb_channel + m];

//#test
        //half2 aaa = __float22half2_rn(a_tmp);
        //if((k==9)&&(id==0)&&(tid==0)){
        //    printf("a_tmp.x=%.10f a_tmp.y=%.10f\n", a_tmp.x, a_tmp.y);
        //    printf("a_tmp.x=%.10f a_tmp.y=%.10f\n", __high2half(aaa), __low2half(aaa));
        //}

        fval_real += a_tmp.x * e_tmp.x;
        fval_real += a_tmp.y * e_tmp.y;
        fval_imag += a_tmp.x * e_tmp.y;
        fval_imag -= a_tmp.y * e_tmp.x;
        __syncthreads();

        for(int s = nb_channel/2; s > 0; s >>= 1){
            fval_real += __shfl_xor(fval_real, s, nb_channel);
            fval_imag += __shfl_xor(fval_imag, s, nb_channel);
        }

        //if((k==9)&&(id==0)&&(i==0)){
        //    printf("k=%d id=%d m=%d G0=%.10lf G1=%.10lf\n", k, id, m, fval_real*fval_real, fval_imag*fval_imag);
        //}

        if(i==0){
            sh_G[m] = fval_real*fval_real + fval_imag*fval_imag;
        }
        __syncthreads();

        for(unsigned int s = blockDim.y / 2; s > 0; s >>= 1){ //s=1
            if(tid<s){
                sh_G[tid] += sh_G[tid + s];
            }
            __syncthreads();
        }

        //if((k==9)&&(id==0)&&(tid==0)){
        //    printf("k=%d id=%d G=%.10f\n", k, id, G[0]);
        //}

        norm_a = 0.0f;
        norm_a += a_tmp.x * a_tmp.x;
        norm_a += a_tmp.y * a_tmp.y;
        __syncthreads();

        for(int s = nb_channel/2; s > 0; s >>= 1){
            norm_a += __shfl_xor(norm_a, s, nb_channel);
        }

        if(tid==0){
            atomicAdd(&Pavg[id*range_num + ir], (float)((norm_a / sh_G[0]) * EV_Weight));
        }
    } //for(ir=0; ir<range_num; ir++){
}

#if 0
__global__
void _gpu_CalcAveragePower2(const float *EigenValue,
    const cuComplex *E,
    const cuComplex *A,
    const int *UsesFreq,
    //int NumSource,
    const float *MSSW,
    const int enable_eigenvalue_weight,
    const int nb_channel,
    const int num_source,
    const int direction_num,
    const int range_num,
    const int pslength,
    float *Pavg
    )
{
    int ir;
#if 1
    half __shared__ sh_G[2];
    half norm_a;
    half EV_Weight;
    half fval_real;
    half fval_imag;
#else
    double __shared__ sh_G[2];
    double norm_a;
    double EV_Weight;
    double fval_real;
    double fval_imag;
#endif
    const int id = blockIdx.x;
    const int k = blockIdx.y;
    const int i = threadIdx.x;
    const int m = threadIdx.y;

    int tid = m*blockDim.x + i;
    //int laneIdx = tid % warpSize; //0~31
    //int warpIdx = tid / warpSize; //0~3

    int nb_channel_1;
    nb_channel_1 = nb_channel - 1;

    if(!UsesFreq[k]){
        return;
    }

    EV_Weight = __float2half(MSSW[k]*(enable_eigenvalue_weight ? sqrt(EigenValue[k*nb_channel + nb_channel_1]) : 1.0f));

    for(ir=0; ir<range_num; ir++){  //max=4??
        //fval_real = 0.0f;
        //fval_imag = 0.0f;

        //cuComplex a_tmp = A[id*range_num*pslength*nb_channel + ir*pslength*nb_channel + k*nb_channel + i];
        //float2 a_tmp = A[id*range_num*pslength*nb_channel + ir*pslength*nb_channel + k*nb_channel + i];
        //cuComplex e_tmp = E[k*nb_channel*nb_channel + i*nb_channel + m];
        half2 a_tmp = __float22half2_rn(A[id*range_num*pslength*nb_channel + ir*pslength*nb_channel + k*nb_channel + i]);
        half2 e_tmp = __float22half2_rn(E[k*nb_channel*nb_channel + i*nb_channel + m]);
        //half a_real = __float2half(a_tmp.x);
        //half a_imag = __float2half(a_tmp.y);
        //half e_real = __float2half(e_tmp.x);
        //half e_imag = __float2half(e_tmp.y);

        //fval_real += a_tmp.x * e_tmp.x;
        fval_real = a_tmp.x * e_tmp.x;
        fval_real += a_tmp.y * e_tmp.y;
        fval_imag += a_tmp.x * e_tmp.y;
        fval_imag -= a_tmp.y * e_tmp.x;
        __syncthreads();

        for(int s = nb_channel/2; s > 0; s >>= 1){
            fval_real += __shfl_xor(fval_real, s, nb_channel);
            fval_imag += __shfl_xor(fval_imag, s, nb_channel);
        }

        //if((k==9)&&(id==0)&&(i==0)){
        //    printf("k=%d id=%d m=%d G0=%.10lf G1=%.10lf\n", k, id, m, fval_real*fval_real, fval_imag*fval_imag);
        //}

        if(i==0){
            sh_G[m] = fval_real*fval_real + fval_imag*fval_imag;
        }
        __syncthreads();

        for(unsigned int s = blockDim.y / 2; s > 0; s >>= 1){ //s=1
            if(tid<s){
                sh_G[tid] += sh_G[tid + s];
            }
            __syncthreads();
        }

        //if((k==9)&&(id==0)&&(tid==0)){
        //    printf("k=%d id=%d G=%.10f\n", k, id, G[0]);
        //}

        norm_a = 0.0f;
        norm_a += a_tmp.x * a_tmp.x;
        norm_a += a_tmp.y * a_tmp.y;
        __syncthreads();

        for(int s = nb_channel/2; s > 0; s >>= 1){
            norm_a += __shfl_xor(norm_a, s, nb_channel);
        }

        if(tid==0){
            atomicAdd(&Pavg[id*range_num + ir], (float)((norm_a / sh_G[0]) * EV_Weight));
        }
    } //for(ir=0; ir<range_num; ir++){
}
#endif

__global__
void _gpu_CalcAverageSum(float *Pavg, float *Pavg_sum, int direction_num, int range_num)
{
    int id = blockIdx.x;
    //int id = blockIdx.x;
    int ir = threadIdx.x;
    int y = threadIdx.y;
    //int ir;
    float tmp;

    //for(id=0; id<direction_num; id++){
    if(y==0) Pavg_sum[id] = 0.0f;
    __syncthreads();

    //tmp = 0.0f;
    //for(ir=0; ir<range_num; ir++){
    //    Pavg_sum[id] += Pavg[id*range_num + ir];
        tmp = Pavg[id*range_num + ir];
    //}
    for(int s = range_num/2; s > 0; s >>= 1){
        tmp += __shfl_xor(tmp, s, range_num);
    }

    //Pavg_sum[id] = 10 * log10(Pavg_sum[id] + 1.0f);
    Pavg_sum[id] = 10 * log10(tmp + 1.0f);
    //}
}


void gpu_CalcAveragePower(float *EigenValue, cuComplex *E, cuComplex *A, int *UsesFreq, int NumSource, float *Pavg, float *MSSW, int enable_eigenvalue_weight, int nb_channel, int num_source, int direction_num, int range_num, int pslength)
{
    int calc_freq = g_upper- g_lower;
    int m_start    = (nb_channel - num_source - 1);

    //dim3 grid(direction_num, pslength);
    dim3 grid(direction_num, calc_freq);
    //dim3 block(m_start+1, nb_channel);
    dim3 block(nb_channel, m_start+1);
    //printf("direction_num = %d pslength=%d\n", grid.x, grid.y);
    //printf("nb_channel = %d m_start=%d\n", block.x, block.y);

    _gpu_CalcAveragePower<<<grid, block>>>(EigenValue,
    //_gpu_CalcAveragePower2<<<grid, block>>>(EigenValue,
        E,
        A,
        UsesFreq,
        MSSW,
        enable_eigenvalue_weight,
        nb_channel,
        num_source,
        direction_num,
        range_num,
        pslength,
        Pavg,
        g_lower
    );

    //dim3 grid2(direction_num, 1);
    //dim3 block2(range_num, 1);
    //_gpu_CalcAverageSum<<<grid2, block2>>>(Pavg, d_Pavg_sum, direction_num, range_num);
}

__global__
void _gpu_CalcAveragePower3(const float *EigenValue,
    const cuComplex *E,
    const cuComplex *A,
    const int *UsesFreq,
    //int NumSource,
    const float *MSSW,
    const int enable_eigenvalue_weight,
    const int nb_channel,
    const int num_source,
    const int height_num,
    const int direction_num,
    const int range_num,
    const int pslength,
    float *Pavg,
    const int st_freq
    )
{
    int ir;
#if 1
    //float __shared__ sh_G[2];
    float __shared__ sh_G[16];  //bug
    float norm_a;
    float EV_Weight;
    float fval_real;
    float fval_imag;
#else
    double __shared__ sh_G[2];
    double norm_a;
    double EV_Weight;
    double fval_real;
    double fval_imag;
#endif
    int ih;
    const int id = blockIdx.x;
    //const int k = blockIdx.y;
    const int k = blockIdx.y + st_freq;
    const int i = threadIdx.x;  //16
    const int m = threadIdx.y;  //14->16  bugfix

    int tid = m*blockDim.x + i;
    //int laneIdx = tid % warpSize; //0~31
    //int warpIdx = tid / warpSize; //0~3

    int m_start    = (nb_channel - num_source - 1);

    int nb_channel_1;
    nb_channel_1 = nb_channel - 1;

    //if(!UsesFreq[k]){
    //    return;
    //}

    EV_Weight = MSSW[k]*(enable_eigenvalue_weight ? sqrt(EigenValue[k*nb_channel + nb_channel_1]) : 1.0f);

    for(ih=0; ih<height_num; ih++){

    for(ir=0; ir<range_num; ir++){  //max=4??
        fval_real = 0.0f;
        fval_imag = 0.0f;

        //AMatrix2[ih][id][ir][k][i].real * E[k][i][m].real;

        //cuComplex a_tmp = A[id*range_num*pslength*nb_channel + ir*pslength*nb_channel + k*nb_channel + i];
        cuComplex a_tmp = A[ih*direction_num*range_num*pslength*nb_channel + id*range_num*pslength*nb_channel + ir*pslength*nb_channel + k*nb_channel + i];

        cuComplex e_tmp = E[k*nb_channel*nb_channel + i*nb_channel + m];

//#test
        //half2 aaa = __float22half2_rn(a_tmp);
        //if((k==9)&&(id==0)&&(tid==0)){
        //if((k==64)&&(id==0)&&(tid==0)){
        //    printf("a_tmp.x=%.10f a_tmp.y=%.10f\n", a_tmp.x, a_tmp.y);
        //    //printf("a_tmp.x=%.10f a_tmp.y=%.10f\n", __high2half(aaa), __low2half(aaa));
        //}

        fval_real += a_tmp.x * e_tmp.x;
        fval_real += a_tmp.y * e_tmp.y;
        fval_imag += a_tmp.x * e_tmp.y;
        fval_imag -= a_tmp.y * e_tmp.x;
        __syncthreads();

        for(int s = nb_channel/2; s > 0; s >>= 1){
            fval_real += __shfl_xor(fval_real, s, nb_channel);
            fval_imag += __shfl_xor(fval_imag, s, nb_channel);
        }

        //if((k==9)&&(id==0)&&(i==0)){
        //if((k==64)&&(id==0)&&(i==0)){
        //    printf("k=%d ih=%d id=%d m=%d G0=%.10lf G1=%.10lf\n", k, ih, id, m, fval_real*fval_real, fval_imag*fval_imag);
        //}
        __syncthreads();

        //if(i == 0)
        if((i == 0)&&(m <= m_start)){
            sh_G[m] = fval_real*fval_real + fval_imag*fval_imag;
            //if((k==64)&&(id==0)&&(i==0)){
            //    printf("k=%d ih=%d id=%d sh_G[%d]=%.10lf\n", k, ih, id, m, sh_G[m]);
            //}
        }
        else{
            sh_G[m] = 0;  //bugfix
        }
        __syncthreads();

        for(unsigned int s = blockDim.y / 2; s > 0; s >>= 1){ //s=1
            if(tid<s){
                sh_G[tid] += sh_G[tid + s];
            }
            __syncthreads();
        }

        //if((k==9)&&(id==0)&&(tid==0)){
        //if((k==64)&&(id==0)&&(tid==0)){
        //    printf("k=%d ih=%d id=%d G=%.10f\n", k, ih, id, sh_G[0]);
        //}

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

        norm_a = 0.0f;
        norm_a += a_tmp.x * a_tmp.x;
        norm_a += a_tmp.y * a_tmp.y;
        __syncthreads();

        for(int s = nb_channel/2; s > 0; s >>= 1){
            norm_a += __shfl_xor(norm_a, s, nb_channel);
        }

        if(tid==0){
            //if((k==64)&&(id==0)){
            //    //printf("k=%d ih=%d id=%d norm_a=%.10f\n", k, ih, id, norm_a);
            //    printf("k=%d ih=%d id=%d norm_a=%.10f G=%f EV_Weight=%f\n", k, ih, id, norm_a, sh_G[0], EV_Weight);
            //}
            //atomicAdd(&Pavg[id*range_num + ir], (float)((norm_a / sh_G[0]) * EV_Weight));
            atomicAdd(&Pavg[ih*direction_num*range_num + id*range_num + ir], (float)((norm_a / sh_G[0]) * EV_Weight));
            //Pavg[k*height_num*direction_num*range_num + ih*direction_num*range_num + id*range_num + ir] = (float)((norm_a / sh_G[0]) * EV_Weight);
        }

    } //ir

    } //ih

}

void gpu_CalcAveragePower2(float *EigenValue, cuComplex *E, cuComplex *A, int *UsesFreq, int NumSource, float *Pavg, float *MSSW, int enable_eigenvalue_weight, int nb_channel, int num_source,
    int height_num, int direction_num, int range_num, int pslength)
{
    int calc_freq = g_upper- g_lower;
    int m_start    = (nb_channel - num_source - 1);
    //printf("m_start=%d\n", m_start);
    //printf("calc_freq=%d(%d~%d)\n", calc_freq, g_lower, g_upper);

    //dim3 grid(direction_num, pslength);
    dim3 grid(direction_num, calc_freq);
    //dim3 block(m_start+1, nb_channel);
    //dim3 block(nb_channel, m_start+1);
    dim3 block(nb_channel, nb_channel);

    //printf("direction_num = %d pslength=%d\n", grid.x, grid.y);
    //printf("nb_channel = %d m_start=%d\n", block.x, m_start);
#if 1
    _gpu_CalcAveragePower3<<<grid, block>>>(EigenValue,
    //_gpu_CalcAveragePower2<<<grid, block>>>(EigenValue,
        E,
        A,
        UsesFreq,
        MSSW,
        enable_eigenvalue_weight,
        nb_channel,
        num_source,
        height_num,
        direction_num,
        range_num,
        pslength,
        Pavg,
        g_lower
        );
#else
    float *test;
    CUDA_SAFE_CALL(cudaMalloc((void **)&test, sizeof(float)*pslength*height_num*direction_num*range_num));
    CUDA_SAFE_CALL(cudaMemset(test, 0, sizeof(float)*pslength*height_num*direction_num*range_num));

    _gpu_CalcAveragePower3<<<grid, block>>>(EigenValue,
    //_gpu_CalcAveragePower2<<<grid, block>>>(EigenValue,
        E,
        A,
        UsesFreq,
        MSSW,
        enable_eigenvalue_weight,
        nb_channel,
        num_source,
        height_num,
        direction_num,
        range_num,
        pslength,
        //Pavg,
        test,
        g_lower
        );

    float *h_test;
    h_test = (float *)malloc(sizeof(float)*pslength*height_num*direction_num*range_num);
    CUDA_SAFE_CALL(cudaMemcpy(h_test, test, sizeof(float)*pslength*height_num*direction_num*range_num, cudaMemcpyDeviceToHost));

    for(int pp=0; pp<pslength; pp++){
        //if(!UsesFreq[pp])continue;

        for(int hh=0; hh<height_num; hh++){
            for(int dd=0; dd<direction_num; dd++){
                printf("(%d, %d, %d) %f\n", pp, hh, dd, h_test[pp*height_num*direction_num + hh*direction_num + dd]);
            }
        }
    }
    exit(0);
#endif

    //dim3 grid2(direction_num, 1);
    //dim3 block2(range_num, 1);
    //_gpu_CalcAverageSum<<<grid2, block2>>>(Pavg, d_Pavg_sum, direction_num, range_num);
}

#if 0
void Evd1(COMPLEX_FLOAT *aa,
    float *dd,
    COMPLEX_FLOAT *vv,
    float *bb,
    float *zz,
    int *UsesFreq,
    int pslength,
    int tf_channel_num
    )
{
    int n;
    int i,j;
    int ip;
    
    n = tf_channel_num;
    
    float *b;
    float *z;
    COMPLEX_FLOAT *a;
    float *d;
    COMPLEX_FLOAT *v;

    int k;
    for(k=0; k<pslength; k++){
        if(!UsesFreq[k]){
            continue;
        }

        //各周波数(k)のポインタ割り当て
        b = &bb[k*16];
        z = &zz[k*16];
        a = &aa[k*n*n];
        d = &dd[k*n];
        v = &vv[k*n*n];

        /* 単位行列の作成 */
        for(j=0; j<n; j++){
            for(i=0; i<n; i++){
                v[j*n + i].real = 0.0f;
                v[j*n + i].imag = 0.0f;
            }
            v[j*n + j].real = 1.0f;
        }

        for(ip=0; ip<n; ip++){
            b[ip] = a[ip*n + ip].real;
            d[ip] = a[ip*n + ip].real;
            z[ip] = 0;
        }
    }
}

//---------------------------------------------------------------------------------------
void Evd2(COMPLEX_FLOAT *aa,
    float *dd,
    COMPLEX_FLOAT *vv,
    float *bb,
    float *zz,
    int *UsesFreq,
    int pslength,
    int tf_channel_num
    )
{
    int n;
    float sm;
    float thresh;
    float g;

    COMPLEX_FLOAT t;
    float c;
    COMPLEX_FLOAT s;
    COMPLEX_FLOAT tau;

    float norm_a;
    float t_tmp;
    float norm_t;

    int i,j;
    int ip, iq;

    float g_real, g_imag;
    float h_real, h_imag;
    float tmp_real, tmp_imag;
    float tmp;

    n = tf_channel_num;

    float *b;
    float *z;
    COMPLEX_FLOAT *a;
    float *d;
    COMPLEX_FLOAT *v;

    int k;
    for(k=0; k<pslength; k++){
        if(!UsesFreq[k]){
            //return;
            continue;
        }

        //各周波数(k)のポインタ割り当て
        b = &bb[k*16];
        z = &zz[k*16];
        a = &aa[k*n*n];
        d = &dd[k*n];
        v = &vv[k*n*n];

        //n=4
        //printf("0~n-1 = %d\n", n-1);
        for(i=0; i<50; i++){
            sm = 0.0f;
            for(ip=0; ip<n-1; ip++){ //0~2
                for(iq=ip+1; iq<n; iq++){
                    //sm += sqrtf(a[ip][iq].real * a[ip][iq].real + a[ip][iq].imag * a[ip][iq].imag);
                    sm += sqrtf(a[ip*n + iq].real * a[ip*n + iq].real + a[ip*n + iq].imag * a[ip*n + iq].imag);
                }
            }

            //収束判定
            if(sm<=1.0e-7){
                //return;
                continue;
            }

            thresh = ((i>=4) ? 0.0f : (0.2f * sm / (float)(n * n)));

            for(ip=0; ip<n-1; ip++){ //0~2
                for(iq=ip+1; iq<n; iq++){ //1~3
                    float abs_a;
                    int idx = ip*n + iq;
                    COMPLEX_FLOAT a_tmp = a[idx];

                    //abs_a = sqrtf(a[ip][iq].real * a[ip][iq].real + a[ip][iq].imag * a[ip][iq].imag);
                    abs_a = sqrtf(a_tmp.real * a_tmp.real + a_tmp.imag * a_tmp.imag);
                    g = 100.0f * abs_a;

                    if((i>4) && (g<=5.0e-9)){
                        //a[ip][iq].real = 0.0f;
                        //a[ip][iq].imag = 0.0f;
                        a[idx].real = 0.0f;
                        a[idx].imag = 0.0f;
                    }
                    else if(abs_a>thresh){
                        tmp = d[iq] - d[ip]; // hの実部(tmp)しか使っていない

                        if(g<=1.0e-8){ // この時点では h は実部しか持たない
                            //t.real =  a[ip][iq].real / tmp; // hの実部(tmp)しか使っていない
                            //t.imag = -a[ip][iq].imag / tmp; // hの実部(tmp)しか使っていない
                            t.real =  a_tmp.real / tmp; // hの実部(tmp)しか使っていない
                            t.imag = -a_tmp.imag / tmp; // hの実部(tmp)しか使っていない
                        }
                        else{
                            //norm_a  = a[ip][iq].real * a[ip][iq].real;
                            //norm_a += a[ip][iq].imag * a[ip][iq].imag;
                            norm_a  = a_tmp.real * a_tmp.real;
                            norm_a += a_tmp.imag * a_tmp.imag;
                            t_tmp  = -tmp + sqrtf(tmp * tmp + 4.0f * norm_a); // h.real=>(d[iq] - d[ip])=>tmp
                            //t.real =  t_tmp * a[ip][iq].real / (2.0f * norm_a);
                            //t.imag = -t_tmp * a[ip][iq].imag / (2.0f * norm_a);
                            t.real =  t_tmp * a_tmp.real / (2.0f * norm_a);
                            t.imag = -t_tmp * a_tmp.imag / (2.0f * norm_a);
                        }

                        norm_t = t.real * t.real + t.imag * t.imag;
                        c = 1.0 / sqrtf(1.0 + norm_t);
                        s.real = t.real * c;
                        s.imag = t.imag * c;
                        tau.real = s.real / (float)(1.0f + c);
                        tau.imag = s.imag / (float)(1.0f + c);
                        //tmp  = t.real * a[ip][iq].real; // hの実部(tmp)しか使っていない
                        //tmp -= t.imag * a[ip][iq].imag; // hの実部(tmp)しか使っていない
                        tmp  = t.real * a_tmp.real; // hの実部(tmp)しか使っていない
                        tmp -= t.imag * a_tmp.imag; // hの実部(tmp)しか使っていない
                        z[ip] -= tmp; // hの実部(tmp)しか使っていない
                        z[iq] += tmp; // hの実部(tmp)しか使っていない
                        d[ip] -= tmp; // hの実部(tmp)しか使っていない
                        d[iq] += tmp; // hの実部(tmp)しか使っていない
                        //a[ip][iq].real = 0.0f;
                        //a[ip][iq].imag = 0.0f;
                        a[idx].real = 0.0f;
                        a[idx].imag = 0.0f;

                        //printf("d[%d] = %.10f d[%d] = %.10f\n", ip, d[ip], iq, d[iq]);
                        for(j=0; j<=ip-1; j++){
                            ////rotate(a, j, ip, j, iq, c, s, tau);
                            //std::complex<T> g = a(j, ip);
                            //std::complex<T> h = a(j, iq);
                            int j_ip = j*n + ip;
                            int j_iq = j*n + iq;
                            //g_real = a[j][ip].real;
                            //g_imag = a[j][ip].imag;
                            g_real = a[j_ip].real;
                            g_imag = a[j_ip].imag;

                            //h_real = a[j][iq].real;
                            //h_imag = a[j][iq].imag;
                            h_real = a[j_iq].real;
                            h_imag = a[j_iq].imag;

                            //a(j, ip) = g - s * (h + g * conj(tau));
                            tmp_real  = h_real;
                            tmp_real += g_real * tau.real;
                            tmp_real += g_imag * tau.imag;
                            tmp_imag  = h_imag;
                            tmp_imag -= g_real * tau.imag;
                            tmp_imag += g_imag * tau.real;
                            tmp  = g_real;
                            tmp -= s.real * tmp_real;
                            tmp += s.imag * tmp_imag;
                            //a[j][ip].real = tmp;
                            a[j_ip].real = tmp;

                            tmp  = g_imag;
                            tmp -= s.real * tmp_imag;
                            tmp -= s.imag * tmp_real;
                            //a[j][ip].imag = tmp;
                            a[j_ip].imag = tmp;

                            //a(j, iq) = h + conj(s) * (g - h * tau);
                            tmp_real  = g_real;
                            tmp_real -= h_real * tau.real;
                            tmp_real += h_imag * tau.imag;
                            tmp_imag  = g_imag;
                            tmp_imag -= h_real * tau.imag;
                            tmp_imag -= h_imag * tau.real;
                            tmp  = h_real;
                            tmp += s.real * tmp_real;
                            tmp += s.imag * tmp_imag;
                            //a[j][iq].real = tmp;
                            a[j_iq].real = tmp;

                            tmp  = h_imag;
                            tmp += s.real * tmp_imag;
                            tmp -= s.imag * tmp_real;
                            //a[j][iq].imag = tmp;
                            a[j_iq].imag = tmp;
                        }

                        for(j=ip+1; j<=iq-1; j++){
                            ////rotate(a, ip, j, j, iq, c, s, tau);
                            //std::complex<T> g = a(ip, j);
                            //std::complex<T> h = a(j, iq);
                            int ip_j = ip*n + j;
                            int j_iq = j*n + iq;

                            //g_real = a[ip][j].real;
                            //g_imag = a[ip][j].imag;
                            //h_real = a[j][iq].real;
                            //h_imag = a[j][iq].imag;
                            g_real = a[ip_j].real;
                            g_imag = a[ip_j].imag;
                            h_real = a[j_iq].real;
                            h_imag = a[j_iq].imag;

                            //a(ip, j) = g - conj(s) * (conj(h) + g * tau);
                            tmp_real  =  h_real;
                            tmp_real +=  g_real * tau.real;
                            tmp_real -=  g_imag * tau.imag;
                            tmp_imag  = -h_imag;
                            tmp_imag +=  g_real * tau.imag;
                            tmp_imag +=  g_imag * tau.real;
                            tmp  = g_real;
                            tmp -= s.real * tmp_real;
                            tmp -= s.imag * tmp_imag;
                            //a[ip][j].real = tmp;
                            a[ip_j].real = tmp;

                            tmp  = g_imag;
                            tmp -= s.real * tmp_imag;
                            tmp += s.imag * tmp_real;
                            //a[ip][j].imag = tmp;
                            a[ip_j].imag = tmp;

                            //a(j, iq) = h + conj(s) * (conj(g) - h * tau);
                            tmp_real  =  g_real;
                            tmp_real -=  h_real * tau.real;
                            tmp_real +=  h_imag * tau.imag;
                            tmp_imag  = -g_imag;
                            tmp_imag -= h_real * tau.imag;
                            tmp_imag -= h_imag * tau.real;
                            tmp  = h_real;
                            tmp += s.real * tmp_real;
                            tmp += s.imag * tmp_imag;
                            //a[j][iq].real = tmp;
                            a[j_iq].real = tmp;

                            tmp  = h_imag;
                            tmp += s.real * tmp_imag;
                            tmp -= s.imag * tmp_real;
                            //a[j][iq].imag = tmp;
                            a[j_iq].imag = tmp;
                        }
                        for(j=iq+1; j<n; j++){
                            ////rotate(a, ip, j, iq, j, c, s, tau);
                            //std::complex<T> g = a(ip, j);
                            //std::complex<T> h = a(iq, j);
                            int ip_j = ip*n + j;
                            int iq_j = iq*n + j;

                            //g_real = a[ip][j].real;
                            //g_imag = a[ip][j].imag;
                            //h_real = a[iq][j].real;
                            //h_imag = a[iq][j].imag;
                            g_real = a[ip_j].real;
                            g_imag = a[ip_j].imag;
                            h_real = a[iq_j].real;
                            h_imag = a[iq_j].imag;

                            //a(ip, j) = g - conj(s) * (h + g * tau);
                            tmp_real  = h_real;
                            tmp_real += g_real * tau.real;
                            tmp_real -= g_imag * tau.imag;
                            tmp_imag  = h_imag;
                            tmp_imag += g_real * tau.imag;
                            tmp_imag += g_imag * tau.real;
                            tmp  = g_real;
                            tmp -= s.real * tmp_real;
                            tmp -= s.imag * tmp_imag;
                            //a[ip][j].real = tmp;
                            a[ip_j].real = tmp;

                            tmp  = g_imag;
                            tmp -= s.real * tmp_imag;
                            tmp += s.imag * tmp_real;
                            //a[ip][j].imag = tmp;
                            a[ip_j].imag = tmp;

                            //a(iq, j) = h + s * (g - h * conj(tau));
                            tmp_real  = g_real;
                            tmp_real -= h_real * tau.real;
                            tmp_real -= h_imag * tau.imag;
                            tmp_imag  = g_imag;
                            tmp_imag += h_real * tau.imag;
                            tmp_imag -= h_imag * tau.real;
                            tmp  = h_real;
                            tmp += s.real * tmp_real;
                            tmp -= s.imag * tmp_imag;
                            //a[iq][j].real = tmp;
                            a[iq_j].real = tmp;

                            tmp  = h_imag;
                            tmp += s.real * tmp_imag;
                            tmp += s.imag * tmp_real;
                            //a[iq][j].imag = tmp;
                            a[iq_j].imag = tmp;
                        }
                        for(j=0; j<n; j++){
                            ////rotate(v, j, ip, j, iq, c, s, tau);
                            //std::complex<T> g = v(j, ip);
                            //std::complex<T> h = v(j, iq);
                            int j_ip = j*n + ip;
                            int j_iq = j*n + iq;

                            //g_real = v[j][ip].real;
                            //g_imag = v[j][ip].imag;
                            //h_real = v[j][iq].real;
                            //h_imag = v[j][iq].imag;
                            g_real = v[j_ip].real;
                            g_imag = v[j_ip].imag;
                            h_real = v[j_iq].real;
                            h_imag = v[j_iq].imag;
                            //LOGI("%d , %d , %d : %g, %g, %g, %g\n", ip, iq, j, g_real, g_imag, h_real, h_imag);

                            //v(j, ip) = g - s * (h + g * conj(tau));
                            tmp_real  = h_real;
                            tmp_real += g_real * tau.real;
                            tmp_real += g_imag * tau.imag;
                            tmp_imag  = h_imag;
                            tmp_imag -= g_real * tau.imag;
                            tmp_imag += g_imag * tau.real;
                            tmp  = g_real;
                            tmp -= s.real * tmp_real;
                            tmp += s.imag * tmp_imag;
                            //v[j][ip].real = tmp;
                            v[j_ip].real = tmp;

                            tmp  = g_imag;
                            tmp -= s.real * tmp_imag;
                            tmp -= s.imag * tmp_real;
                            //v[j][ip].imag = tmp;
                            v[j_ip].imag = tmp;
                            //                        LOGI("<%g, %g>\n", tmp_real, tmp_imag);
                            //                        LOGI("<%g, %g>\n", s.real, s.imag);
                            //                        LOGI("[%g, %g]\n", s.real * tmp_imag , s.imag * tmp_real);
                            //v(j, iq) = h + conj(s) * (g - h * tau);
                            tmp_real  = g_real;
                            tmp_real -= h_real * tau.real;
                            tmp_real += h_imag * tau.imag;
                            tmp_imag  = g_imag;
                            tmp_imag -= h_real * tau.imag;
                            tmp_imag -= h_imag * tau.real;
                            tmp  = h_real;
                            tmp += s.real * tmp_real;
                            tmp += s.imag * tmp_imag;
                            //v[j][iq].real = tmp;
                            v[j_iq].real = tmp;

                            tmp  = h_imag;
                            tmp += s.real * tmp_imag;
                            tmp -= s.imag * tmp_real;
                            //v[j][iq].imag = tmp;
                            v[j_iq].imag = tmp;
                        }
                    } //else if (abs_a > thresh)
                }//ip
            }//iq

            for(ip=0; ip<n; ip++){
                //LOGI("z[%d] = %g\n", ip, z[ip]);
                b[ip] += z[ip];
                d[ip] = b[ip];
                z[ip] = 0.0;
            }
        } //i iteration loop
    }
}

//---------------------------------------------------------------------------------------
void Evd3( float *dd,
    COMPLEX_FLOAT *vv,
    int *UsesFreq,
    int pslength,
    int tf_channel_num
    )
{
    int n;
    int i,j;

    float d_tmp;
    float v_tmp;

    //n = localize_music_info.tf_channel_num;
    n = tf_channel_num;

    float *d;
    COMPLEX_FLOAT *v;

    int k;
    for(k=0; k<pslength; k++){
        if(!UsesFreq[k]){
            //return;
            continue;
        }

        //各周波数(k)のポインタ割り当て
        d = &dd[k*n];
        v = &vv[k*n*n];

        // sorting eigenvalues in ascending order
        for(i=0; i<n-1; i++){
            float min = d[i];
            int imin = i;
            for(j=i+1; j<n; j++){
                if(min>d[j]){
                    min = d[j];
                    imin = j;
                }
            }
            if(imin != i){
                //std::swap(d[i], d[imin]);
                d_tmp   = d[i];
                d[i]    = d[imin];
                d[imin] = d_tmp;
                //ublas::column(v, i).swap(ublas::column(v, imin));
                for(j=0; j<n; j++){
                    //v_tmp           = v[j][i].real;
                    //v[j][i].real    = v[j][imin].real;
                    //v[j][imin].real = t_tmp;
                    v_tmp           = v[j*n + i].real;
                    v[j*n + i].real    = v[j*n + imin].real;
                    //v[j*n + imin].real = t_tmp;
                    v[j*n + imin].real = v_tmp;

                    //v_tmp           = v[j][i].imag;
                    //v[j][i].imag    = v[j][imin].imag;
                    //v[j][imin].imag = t_tmp;
                    v_tmp           = v[j*n + i].imag;
                    v[j*n + i].imag    = v[j*n + imin].imag;
                    //v[j*n + imin].imag = t_tmp;
                    v[j*n + imin].imag = v_tmp;
                }
            }
        }
    }
}

void cpu_Evd(COMPLEX_FLOAT *a,
    float *d,
    COMPLEX_FLOAT *v,
    float *b,
    float *z,
    int *UsesFreq,
    int pslength,
    int tf_channel_num
    )
{
    Evd1(a, d, v, b, z, UsesFreq, pslength, tf_channel_num);
    Evd2(a, d, v, b, z, UsesFreq, pslength, tf_channel_num);
    Evd3(d, v, UsesFreq, pslength, tf_channel_num);
}
#endif

__global__
void _Evd1(cuComplex *aa,
    float *dd,
    cuComplex *vv,
    float *bb,
    float *zz,
    int *UsesFreq,
    int pslength,
    //int tf_channel_num
    int n,
    int st_freq
    )
{

    float *b;
    float *z;
    cuComplex *a;
    float *d;
    cuComplex *v;

    //int k = blockIdx.x;
    int k = blockIdx.x + st_freq;
    int j = threadIdx.y;
    int i = threadIdx.x;
    int ip = threadIdx.x;

    //for(k=0; k<pslength; k++){
        //if(!UsesFreq[k]){
        //        return;
        //        //continue;
        //}

        //各周波数(k)のポインタ割り当て
        b = &bb[k*16];
        z = &zz[k*16];
        a = &aa[k*n*n];
        d = &dd[k*n];
        v = &vv[k*n*n];

        /* 単位行列の作成 */
        //for(j=0; j<n; j++){
        //    for(i=0; i<n; i++){
        //        v[j*n + i].x = 0.0f;
        //        v[j*n + i].y = 0.0f;
        //    }
        //    v[j*n + j].x = 1.0f;
        //}
        cuComplex tmp;
        if(i==j){
            tmp.x = 1.0f;
            tmp.y = 0.0f;
        }else{
            tmp.x = 0.0f;
            tmp.y = 0.0f;
        }
        v[j*n + i] = tmp;
        //__syncthreads();

        if(j==0){
            //for(ip=0; ip<n; ip++){
               tmp = a[ip*n + ip];
               b[ip] = tmp.x; //real
               d[ip] = tmp.x; //real
               z[ip] = 0;
            //}
        }
    //}
}

#define USE_EVD2_SHARED_MEM
//---------------------------------------------------------------------------------------
__global__
void _Evd2(cuComplex *aa,
    float *dd,
    cuComplex *vv,
    float *bb,
    float *zz,
    int *UsesFreq,
    int pslength,
    //int tf_channel_num
    int n,
    int st_freq
    )
{
    //int n;
    float sm;
    float thresh;
    float g;

    cuComplex t;
    float c;
    cuComplex s;
    cuComplex tau;

    float norm_a;
    float t_tmp;
    float norm_t;

    int i,j;
    int ip, iq;

    float g_real, g_imag;
    float h_real, h_imag;
    float tmp_real, tmp_imag;
    float tmp;

    //n = tf_channel_num;

    float *b;
    float *z;
#ifdef USE_EVD2_SHARED_MEM
    //cuComplex __shared__ a[16]; //4*4
    cuComplex __shared__ a[MAX_CH_NUM_2]; //4*4
#else
    cuComplex *a;
#endif
    float *d;
    cuComplex *v;


    //int k = blockIdx.x;
    int k = blockIdx.x + st_freq;

    //for(k=0; k<pslength; k++){
        //if(!UsesFreq[k]){
        //    return;
        //    //continue;
        //}

        //各周波数(k)のポインタ割り当て
        b = &bb[k*16];
        z = &zz[k*16];
#ifndef USE_EVD2_SHARED_MEM
        a = &aa[k*n*n];
#endif
        d = &dd[k*n];
        v = &vv[k*n*n];

#ifdef USE_EVD2_SHARED_MEM
        //shared memory
        //for(int jj=0; jj<16; jj++){
        for(int jj=0; jj<MAX_CH_NUM_2; jj++){
            a[jj] = aa[k*n*n + jj];
        }
#endif

        //n=4
        //printf("0~n-1 = %d\n", n-1);
        for(i=0; i<50; i++){
            sm = 0.0f;
            for(ip=0; ip<n-1; ip++){ //0~2
                for(iq=ip+1; iq<n; iq++){
                    //sm += sqrtf(a[ip][iq].real * a[ip][iq].real + a[ip][iq].imag * a[ip][iq].imag);
                    sm += sqrtf(a[ip*n + iq].x * a[ip*n + iq].x + a[ip*n + iq].y * a[ip*n + iq].y);
                }
            }

            //収束判定
            if(sm <= 1.0e-7){
                return;
                //continue;
            }

            thresh = ((i>=4) ? 0.0f : (0.2f * sm / (float)(n * n)));

            for(ip=0; ip<n-1; ip++){ //0~2
                for(iq=ip+1; iq<n; iq++){ //1~3
                    float abs_a;
                    int idx = ip*n + iq;
                    cuComplex a_tmp = a[idx];

                    //abs_a = sqrtf(a[ip][iq].real * a[ip][iq].real + a[ip][iq].imag * a[ip][iq].imag);
                    abs_a = sqrtf(a_tmp.x * a_tmp.x + a_tmp.y * a_tmp.y);
                    g = 100.0f * abs_a;

                    if ((i > 4) && (g <= 5.0e-9)){
                        //a[ip][iq].real = 0.0f;
                        //a[ip][iq].imag = 0.0f;
                        a[idx].x = 0.0f;
                        a[idx].y = 0.0f;
                    }
                    else if(abs_a > thresh){
                        tmp = d[iq] - d[ip]; // hの実部(tmp)しか使っていない

                        if(g <= 1.0e-8){ // この時点では h は実部しか持たない
                            //t.real =  a[ip][iq].real / tmp; // hの実部(tmp)しか使っていない
                            //t.imag = -a[ip][iq].imag / tmp; // hの実部(tmp)しか使っていない
                            t.x =  a_tmp.x / tmp; // hの実部(tmp)しか使っていない
                            t.y = -a_tmp.y / tmp; // hの実部(tmp)しか使っていない
                        }
                        else{
                            //norm_a  = a[ip][iq].real * a[ip][iq].real;
                            //norm_a += a[ip][iq].imag * a[ip][iq].imag;
                            norm_a  = a_tmp.x * a_tmp.x;
                            norm_a += a_tmp.y * a_tmp.y;
                            t_tmp  = -tmp + sqrtf(tmp * tmp + 4.0f * norm_a); // h.real=>(d[iq] - d[ip])=>tmp
                            //t.real =  t_tmp * a[ip][iq].real / (2.0f * norm_a);
                            //t.imag = -t_tmp * a[ip][iq].imag / (2.0f * norm_a);
                            t.x =  t_tmp * a_tmp.x / (2.0f * norm_a);
                            t.y = -t_tmp * a_tmp.y / (2.0f * norm_a);
                        }

                        norm_t = t.x * t.x + t.y * t.y;
                        c = 1.0 / sqrtf(1.0 + norm_t);
                        s.x = t.x * c;
                        s.y = t.y * c;
                        tau.x = s.x / (float)(1.0f + c);
                        tau.y = s.y / (float)(1.0f + c);
                        //tmp  = t.real * a[ip][iq].real; // hの実部(tmp)しか使っていない
                        //tmp -= t.imag * a[ip][iq].imag; // hの実部(tmp)しか使っていない
                        tmp  = t.x * a_tmp.x; // hの実部(tmp)しか使っていない
                        tmp -= t.y * a_tmp.y; // hの実部(tmp)しか使っていない
                        z[ip] -= tmp; // hの実部(tmp)しか使っていない
                        z[iq] += tmp; // hの実部(tmp)しか使っていない
                        d[ip] -= tmp; // hの実部(tmp)しか使っていない
                        d[iq] += tmp; // hの実部(tmp)しか使っていない
                        //a[ip][iq].real = 0.0f;
                        //a[ip][iq].imag = 0.0f;
                        a[idx].x = 0.0f;
                        a[idx].y = 0.0f;

                        //printf("d[%d] = %.10f d[%d] = %.10f\n", ip, d[ip], iq, d[iq]);

                        for(j=0; j<=ip-1; j++){
                            ////rotate(a, j, ip, j, iq, c, s, tau);
                            //std::complex<T> g = a(j, ip);
                            //std::complex<T> h = a(j, iq);
                            int j_ip = j*n + ip;
                            int j_iq = j*n + iq;
                            //g_real = a[j][ip].real;
                            //g_imag = a[j][ip].imag;
                            g_real = a[j_ip].x;
                            g_imag = a[j_ip].y;

                            //h_real = a[j][iq].real;
                            //h_imag = a[j][iq].imag;
                            h_real = a[j_iq].x;
                            h_imag = a[j_iq].y;

                            //a(j, ip) = g - s * (h + g * conj(tau));
                            tmp_real  = h_real;
                            tmp_real += g_real * tau.x;
                            tmp_real += g_imag * tau.y;
                            tmp_imag  = h_imag;
                            tmp_imag -= g_real * tau.y;
                            tmp_imag += g_imag * tau.x;
                            tmp  = g_real;
                            tmp -= s.x * tmp_real;
                            tmp += s.y * tmp_imag;
                            //a[j][ip].real = tmp;
                            a[j_ip].x = tmp;

                            tmp  = g_imag;
                            tmp -= s.x * tmp_imag;
                            tmp -= s.y * tmp_real;
                            //a[j][ip].imag = tmp;
                            a[j_ip].y = tmp;

                            //a(j, iq) = h + conj(s) * (g - h * tau);
                            tmp_real  = g_real;
                            tmp_real -= h_real * tau.x;
                            tmp_real += h_imag * tau.y;
                            tmp_imag  = g_imag;
                            tmp_imag -= h_real * tau.y;
                            tmp_imag -= h_imag * tau.x;
                            tmp  = h_real;
                            tmp += s.x * tmp_real;
                            tmp += s.y * tmp_imag;
                            //a[j][iq].real = tmp;
                            a[j_iq].x = tmp;

                            tmp  = h_imag;
                            tmp += s.x * tmp_imag;
                            tmp -= s.y * tmp_real;
                            //a[j][iq].imag = tmp;
                            a[j_iq].y = tmp;
                        }

                        for(j=ip+1; j<=iq-1; j++){
                            ////rotate(a, ip, j, j, iq, c, s, tau);
                            //std::complex<T> g = a(ip, j);
                            //std::complex<T> h = a(j, iq);
                            int ip_j = ip*n + j;
                            int j_iq = j*n + iq;

                            //g_real = a[ip][j].real;
                            //g_imag = a[ip][j].imag;
                            //h_real = a[j][iq].real;
                            //h_imag = a[j][iq].imag;
                            g_real = a[ip_j].x;
                            g_imag = a[ip_j].y;
                            h_real = a[j_iq].x;
                            h_imag = a[j_iq].y;

                            //a(ip, j) = g - conj(s) * (conj(h) + g * tau);
                            tmp_real  =  h_real;
                            tmp_real +=  g_real * tau.x;
                            tmp_real -=  g_imag * tau.y;
                            tmp_imag  = -h_imag;
                            tmp_imag +=  g_real * tau.y;
                            tmp_imag +=  g_imag * tau.x;
                            tmp  = g_real;
                            tmp -= s.x * tmp_real;
                            tmp -= s.y * tmp_imag;
                            //a[ip][j].real = tmp;
                            a[ip_j].x = tmp;

                            tmp  = g_imag;
                            tmp -= s.x * tmp_imag;
                            tmp += s.y * tmp_real;
                            //a[ip][j].imag = tmp;
                            a[ip_j].y = tmp;

                            //a(j, iq) = h + conj(s) * (conj(g) - h * tau);
                            tmp_real  =  g_real;
                            tmp_real -=  h_real * tau.x;
                            tmp_real +=  h_imag * tau.y;
                            tmp_imag  = -g_imag;
                            tmp_imag -= h_real * tau.y;
                            tmp_imag -= h_imag * tau.x;
                            tmp  = h_real;
                            tmp += s.x * tmp_real;
                            tmp += s.y * tmp_imag;
                            //a[j][iq].real = tmp;
                            a[j_iq].x = tmp;

                            tmp  = h_imag;
                            tmp += s.x * tmp_imag;
                            tmp -= s.y * tmp_real;
                            //a[j][iq].imag = tmp;
                            a[j_iq].y = tmp;
                        }
                        for(j=iq+1; j<n; j++){
                            ////rotate(a, ip, j, iq, j, c, s, tau);
                            //std::complex<T> g = a(ip, j);
                            //std::complex<T> h = a(iq, j);
                            int ip_j = ip*n + j;
                            int iq_j = iq*n + j;

                            //g_real = a[ip][j].real;
                            //g_imag = a[ip][j].imag;
                            //h_real = a[iq][j].real;
                            //h_imag = a[iq][j].imag;
                            g_real = a[ip_j].x;
                            g_imag = a[ip_j].y;
                            h_real = a[iq_j].x;
                            h_imag = a[iq_j].y;

                            //a(ip, j) = g - conj(s) * (h + g * tau);
                            tmp_real  = h_real;
                            tmp_real += g_real * tau.x;
                            tmp_real -= g_imag * tau.y;
                            tmp_imag  = h_imag;
                            tmp_imag += g_real * tau.y;
                            tmp_imag += g_imag * tau.x;
                            tmp  = g_real;
                            tmp -= s.x * tmp_real;
                            tmp -= s.y * tmp_imag;
                            //a[ip][j].real = tmp;
                            a[ip_j].x = tmp;

                            tmp  = g_imag;
                            tmp -= s.x * tmp_imag;
                            tmp += s.y * tmp_real;
                            //a[ip][j].imag = tmp;
                            a[ip_j].y = tmp;

                            //a(iq, j) = h + s * (g - h * conj(tau));
                            tmp_real  = g_real;
                            tmp_real -= h_real * tau.x;
                            tmp_real -= h_imag * tau.y;
                            tmp_imag  = g_imag;
                            tmp_imag += h_real * tau.y;
                            tmp_imag -= h_imag * tau.x;
                            tmp  = h_real;
                            tmp += s.x * tmp_real;
                            tmp -= s.y * tmp_imag;
                            //a[iq][j].real = tmp;
                            a[iq_j].x = tmp;

                            tmp  = h_imag;
                            tmp += s.x * tmp_imag;
                            tmp += s.y * tmp_real;
                            //a[iq][j].imag = tmp;
                            a[iq_j].y = tmp;
                        }
                        for(j=0; j<n; j++){
                            ////rotate(v, j, ip, j, iq, c, s, tau);
                            //std::complex<T> g = v(j, ip);
                            //std::complex<T> h = v(j, iq);
                            int j_ip = j*n + ip;
                            int j_iq = j*n + iq;

                            //g_real = v[j][ip].real;
                            //g_imag = v[j][ip].imag;
                            //h_real = v[j][iq].real;
                            //h_imag = v[j][iq].imag;
                            g_real = v[j_ip].x;
                            g_imag = v[j_ip].y;
                            h_real = v[j_iq].x;
                            h_imag = v[j_iq].y;
                            //LOGI("%d , %d , %d : %g, %g, %g, %g\n", ip, iq, j, g_real, g_imag, h_real, h_imag);

                            //v(j, ip) = g - s * (h + g * conj(tau));
                            tmp_real  = h_real;
                            tmp_real += g_real * tau.x;
                            tmp_real += g_imag * tau.y;
                            tmp_imag  = h_imag;
                            tmp_imag -= g_real * tau.y;
                            tmp_imag += g_imag * tau.x;
                            tmp  = g_real;
                            tmp -= s.x * tmp_real;
                            tmp += s.y * tmp_imag;
                            //v[j][ip].real = tmp;
                            v[j_ip].x = tmp;

                            tmp  = g_imag;
                            tmp -= s.x * tmp_imag;
                            tmp -= s.y * tmp_real;
                            //v[j][ip].imag = tmp;
                            v[j_ip].y = tmp;
                            //LOGI("<%g, %g>\n", tmp_real, tmp_imag);
                            //LOGI("<%g, %g>\n", s.real, s.imag);
                            //LOGI("[%g, %g]\n", s.real * tmp_imag , s.imag * tmp_real);
                            //v(j, iq) = h + conj(s) * (g - h * tau);
                            tmp_real  = g_real;
                            tmp_real -= h_real * tau.x;
                            tmp_real += h_imag * tau.y;
                            tmp_imag  = g_imag;
                            tmp_imag -= h_real * tau.y;
                            tmp_imag -= h_imag * tau.x;
                            tmp  = h_real;
                            tmp += s.x * tmp_real;
                            tmp += s.y * tmp_imag;
                            //v[j][iq].real = tmp;
                            v[j_iq].x = tmp;

                            tmp  = h_imag;
                            tmp += s.x * tmp_imag;
                            tmp -= s.y * tmp_real;
                            //v[j][iq].imag = tmp;
                            v[j_iq].y = tmp;
                        }
                    } //else if (abs_a > thresh)
                }//ip
            }//iq

            for(ip=0; ip<n; ip++){
                //LOGI("z[%d] = %g\n", ip, z[ip]);
                b[ip] += z[ip];
                d[ip] = b[ip];
                z[ip] = 0.0;
            }
        } //i iteration loop
#if 0
    //}
}

//---------------------------------------------------------------------------------------
__global__
void _Evd3(float *dd,
    cuComplex *vv,
    int *UsesFreq,
    int pslength,
    //int tf_channel_num
    int n,
    int st_freq
    )
{
   int i,j;

    float d_tmp;
    float v_tmp;

    //n = localize_music_info.tf_channel_num;
    //n = tf_channel_num;

    float *d;
    cuComplex *v;

    //int k = blockIdx.x;
    int k = blockIdx.x + st_freq;

    //for(k=0; k<pslength; k++){
        //if(!UsesFreq[k]){
        //    return;
        //    //continue;
        //}

        //各周波数(k)のポインタ割り当て
        d = &dd[k*n];
        v = &vv[k*n*n];

#endif
        float d_tmp;
        float v_tmp;

        // sorting eigenvalues in ascending order
        for(i=0; i<n-1; i++){
            float min = d[i];
            int imin = i;
            for(j=i+1; j<n; j++){
                if(min>d[j]){
                    min = d[j];
                    imin = j;
                }
            }
            if(imin != i){
                //std::swap(d[i], d[imin]);
                d_tmp   = d[i];
                d[i]    = d[imin];
                d[imin] = d_tmp;
                //ublas::column(v, i).swap(ublas::column(v, imin));
                for(j=0; j<n; j++){
                    //v_tmp           = v[j][i].real;
                    //v[j][i].real    = v[j][imin].real;
                    //v[j][imin].real = t_tmp;
                    v_tmp           = v[j*n + i].x;
                    v[j*n + i].x    = v[j*n + imin].x;
                    //bug
                    //v[j*n + imin].real = t_tmp;
                    v[j*n + imin].x = v_tmp;

                    //v_tmp           = v[j][i].imag;
                    //v[j][i].imag    = v[j][imin].imag;
                    //v[j][imin].imag = t_tmp;
                    v_tmp           = v[j*n + i].y;
                    v[j*n + i].y    = v[j*n + imin].y;
                    //bug
                    //v[j*n + imin].imag = t_tmp;
                    v[j*n + imin].y = v_tmp;
                }
            }
        }
    //}
}


void gpu_Evd(cuComplex *a,
    float *d,
    cuComplex *v,
    float *b,
    float *z,
    int *UsesFreq,
    int pslength,
    int tf_channel_num
    )
{
    //printf("MAX_CH_NUM_2=%d\n", MAX_CH_NUM_2);
    int calc_freq = g_upper- g_lower;

    //dim3 grid1(pslength, 1);
    dim3 grid1(calc_freq, 1);
    //dim3 block1(1, 1);
    dim3 block1(tf_channel_num, tf_channel_num);
    _Evd1<<<grid1, block1>>>(a, d, v, b, z, UsesFreq, pslength, tf_channel_num, g_lower);

    //printf("tf_channel_num=%d\n", tf_channel_num);
    //dim3 grid2(pslength, 1);
    dim3 grid2(calc_freq, 1);
    dim3 block2(1, 1);
    //_Evd2<<<grid2, block2>>>(a, d, v, b, z, UsesFreq, pslength, tf_channel_num);
    _Evd2<<<grid2, block2>>>(a, d, v, b, z, UsesFreq, pslength, tf_channel_num, g_lower);

#if 0
    //dim3 grid3(pslength, 1);
    dim3 grid3(calc_freq, 1);
    //dim3 block1(1, 1);
    dim3 block3(1, 1);
    _Evd3<<<grid3, block3>>>(d, v, UsesFreq, pslength, tf_channel_num, g_lower);
#endif
}

//float ABS(float a)
//{
//    return (a < 0.0f ? -a : a > 0.0f ? a : 0.0f);
//}

#define ABS(a) (a < 0.0f ? -a : a > 0.0f ? a : 0.0f)

//void cpu_Svd(COMPLEX_FLOAT **a, float *s, COMPLEX_FLOAT **u, COMPLEX_FLOAT **v,
//    int m, int n)

// a -> a[m][n]
// u -> u[m][n]
// v -> v[m][n]


void cpu_Svd(cuComplex *aa, float *ss, cuComplex *uu, cuComplex *vv,
    int m, int n,
    int *UsesFreq, int pslength,
    float *bb, float *cc, float *tt
    )
{
    //int m;
    //int n;
    int p;  // transformation Conj(Tran(u)) is applied to the p vectors given in columns n, n+1, ..., n+p-1 of matrix a
    int nu; // considered number of cols of u
    int nv; // considered number of cols of v
    
    //float b[16];
    //float c[16];
    //float t[16];
    float *b;
    float *c;
    float *t;
    
    //COMPLEX_FLOAT q;
    cuComplex q;
    //COMPLEX_FLOAT r;
    cuComplex r;
    int i, j, k, k1, L, L1, nM1, np;
    
    float cs, eps, eta, f, g, h;
    float sn;
    float tol, w, x, y, z;
    float tmp, tmp2, tmp_real, tmp_imag;
    //float f_real;
    //float f_imag;

    int kk;
    cuComplex *a;
    float *s;
    cuComplex *u;
    cuComplex *v;

    for(kk=0; kk<pslength; kk++){

        if(!UsesFreq[kk]){
            continue;
        }

        a = &aa[kk*m*n];
        s = &ss[kk*n]; //m or n?
        u = &uu[kk*m*n];
        v = &vv[kk*m*n];

        b = &bb[kk*MAX_CH_NUM];
        c = &cc[kk*MAX_CH_NUM];
        t = &tt[kk*MAX_CH_NUM];

//----------------------------------------------------------------
    //m = amatrix_info.mic_num;
    //n = amatrix_info.mic_num;
    //m = localize_music_info.tf_channel_num;
    //n = localize_music_info.tf_channel_num;

    //以下３つはconst
    p = 0;
    nu = m;
    nv = n;
    
    //以下4つはconst
    eta = 1.5E-07F;
    tol = 1.5E-31F;
    np  = n + p;
    nM1 = n - 1;

    //Lは最初の関数は未使用
    L   = 0;  //loop変数

    //以下２つは最初の関数だけ行う
    // HOUSEHOLDER REDUCTION
    c[0] = 0.0F;
    k = 0; // TOLERANCE FOR NEGLIGIBLE ELEMENTS後(while loop)は初期化される
    
    //デバック
    //LOGI("(%f, %f), (%f, %f)\n", a[0][0].real, a[0][0].imag, a[0][1].real, a[0][1].imag);

    while(1){
        k1 = k + 1;
        // ELIMINATION OF a(i,k), i = k, ..., m-1
        z = 0.0F;

        for(i = k; i < m; i++){
            //z += norm(a(i,k));
            //z += a[i][k].real * a[i][k].real;
            //z += a[i][k].imag * a[i][k].imag;
            z += a[i*n + k].x * a[i*n + k].x;
            z += a[i*n + k].y * a[i*n + k].y;
        }
        //デバック
        //LOGI("%d : %g\n", k, z);

        b[k] = 0.0F;
        if(z > tol){
            //z = (float)sqrt(z);
            z = sqrtf(z);
            b[k] = z;

            //w = abs(a(k,k));
            //w = sqrt(a[k][k].real * a[k][k].real + a[k][k].imag * a[k][k].imag);
            //w = sqrtf(a[k][k].real * a[k][k].real + a[k][k].imag * a[k][k].imag);
            w = sqrtf(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);

            if(w != 0.0F){
                //q = a(k,k) / w;
                //q.real = a[k][k].real / w;
                //q.y = a[k][k].imag / w;
                tmp = 1.0f / w;
                //q.real = a[k][k].real * tmp;
                //q.y = a[k][k].imag * tmp;
                q.x = a[k*n + k].x * tmp;
                q.y = a[k*n + k].y * tmp;
            }
            else{
                q.x = 1.0f;
                q.y = 0.0f;
            }
            //a(k,k) = q * (z + w);
            //a[k][k].real = q.real * (z + w);
            //a[k][k].imag = q.y * (z + w);
            tmp = (z + w);
            //a[k][k].real = q.real * tmp;
            //a[k][k].imag = q.y * tmp;
            a[k*n + k].x = q.x * tmp;
            a[k*n + k].y = q.y * tmp;
            tmp = 1.0f / (tmp * z);

            if(k != np - 1){
                for(j=k1; j<np; j++){
                    //q = std::complex<T>(0.0F, 0.0F);
                    q.x = 0.0f;
                    q.y = 0.0f;

                    for(i=k; i<m; i++){
                        //q += conj(a(i,k)) * a(i,j);
                        //q.x += a[i][k].real * a[i][j].real;
                        //q.x += a[i][k].imag * a[i][j].imag;
                        //q.y += a[i][k].real * a[i][j].imag;
                        //q.y -= a[i][k].imag * a[i][j].real;
                        q.x += a[i*n + k].x * a[i*n + j].x;
                        q.x += a[i*n + k].y * a[i*n + j].y;
                        q.y += a[i*n + k].x * a[i*n + j].y;
                        q.y -= a[i*n + k].y * a[i*n + j].x;
                    }

                    //q /= z * (z + w);
                    ////q.x = q.x / (z * (z + w));
                    ////q.y = q.y / (z * (z + w));
                    q.x *= tmp;
                    q.y *= tmp;
                    for(i=k; i<m; i++){
                        //a(i,j) -= q * a(i,k);
                        //tmp_real  = q.x * a[i][k].real;
                        //tmp_real -= q.y * a[i][k].imag;
                        //tmp_imag  = q.x * a[i][k].imag;
                        //tmp_imag += q.y * a[i][k].real;
                        tmp_real  = q.x * a[i*n + k].x;
                        tmp_real -= q.y * a[i*n + k].y;
                        tmp_imag  = q.x * a[i*n + k].y;
                        tmp_imag += q.y * a[i*n + k].x;
                        //a[i][j].real -= tmp_real;
                        //a[i][j].imag -= tmp_imag;
                        a[i*n + j].x -= tmp_real;
                        a[i*n + j].y -= tmp_imag;
                    }
                }
            }
            // PHASE TRANSFORMATION
            //q = -conj(a(k,k)) / abs(a(k,k));
            //w = sqrt(a[k][k].real * a[k][k].real + a[k][k].imag * a[k][k].imag);
            //w = sqrtf(a[k][k].real * a[k][k].real + a[k][k].imag * a[k][k].imag);
            w = sqrtf(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);
            //q.x = -a[k][k].real / w;
            //q.y =  a[k][k].imag / w;
            tmp = 1.0f / w;
            //q.x = -a[k][k].real * tmp;
            //q.y =  a[k][k].imag * tmp;
            q.x = -a[k*n + k].x * tmp;
            q.y =  a[k*n + k].y * tmp;

            //デバック
            //LOGI("q = (%g,%g)\n", q.x, q.y);

            for(j=k1; j<np; j++){
                //a(k,j) *= q;
                //tmp_real  = a[k][j].real * q.x;
                //tmp_real -= a[k][j].imag * q.y;
                //tmp_imag  = a[k][j].real * q.y;
                //tmp_imag += a[k][j].imag * q.x;
                tmp_real  = a[k*n + j].x * q.x;
                tmp_real -= a[k*n + j].y * q.y;
                tmp_imag  = a[k*n + j].x * q.y;
                tmp_imag += a[k*n + j].y * q.x;
                //a[k][j].real = tmp_real;
                //a[k][j].imag = tmp_imag;
                a[k*n + j].x = tmp_real;
                a[k*n + j].y = tmp_imag;
            }
        }
#if 0
        //デバック
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[0][0].real, a[0][0].imag,
                a[0][1].real, a[0][1].imag,
                a[0][2].real, a[0][2].imag,
                a[0][3].real, a[0][3].imag);
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[1][0].real, a[1][0].imag,
                a[1][1].real, a[1][1].imag,
                a[1][2].real, a[1][2].imag,
                a[1][3].real, a[1][3].imag);
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[2][0].real, a[2][0].imag,
                a[2][1].real, a[2][1].imag,
                a[2][2].real, a[2][2].imag,
                a[2][3].real, a[2][3].imag);
#endif
        // ELIMINATION OF a(k][j], j = k+2, ..., n-1
        if(k==nM1) break;
        z = 0.0F;
        for(j=k1; j<n; j++){
            //z += norm(a(k,j));
            z += a[k*n + j].x * a[k*n + j].x;
            z += a[k*n + j].y * a[k*n + j].y;
        }

        c[k1] = 0.0F;
        if(z > tol){
            //z = (float)sqrt(z);
            z = sqrtf(z);
            c[k1] = z;

            //w = abs(a(k,k1));
            //w = sqrt(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            w = sqrtf(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);

            if(w != 0.0F){
                //q = a(k,k1) / w;
                //q.x = a[k*n + k1].x / w;
                //q.y = a[k*n + k1].y / w;
                tmp = 1.0f / w;
                q.x = a[k*n + k1].x * tmp;
                q.y = a[k*n + k1].y * tmp;
            }
            else{
                q.x = 1.0f;
                q.y = 0.0f;
            }
            //a(k,k1) = q * (z + w);
            tmp = (z + w);
            ////a[k*n + k1].x = q.x * (z + w);
            ////a[k*n + k1].y = q.y * (z + w);
            a[k*n + k1].x = q.x * tmp;
            a[k*n + k1].y = q.y * tmp;
            tmp = 1.0f / (tmp * z);

            for(i=k1; i<m; i++){
                //q = std::complex<T>(0.0F, 0.0F);
                q.x = 0.0f;
                q.y = 0.0f;

                for(j=k1; j<n; j++){
	                //q += conj(a(k,j)) * a(i,j);
	                q.x += a[k*n + j].x * a[i*n + j].x;
	                q.x += a[k*n + j].y * a[i*n + j].y;
	                q.y += a[k*n + j].x * a[i*n + j].y;
	                q.y -= a[k*n + j].y * a[i*n + j].x;
                }

                //q /= z * (z + w);
                ////q.x = q.x / (z * (z + w));
                ////q.y = q.y / (z * (z + w));
                q.x *= tmp;
                q.y *= tmp;
                for(j=k1; j<n; j++){
	                //a(i,j) -= q * a(k,j);
	                tmp_real  = q.x * a[k*n + j].x;
	                tmp_real -= q.y * a[k*n + j].y;
	                tmp_imag  = q.x * a[k*n + j].y;
	                tmp_imag += q.y * a[k*n + j].x;
	                a[i*n + j].x -= tmp_real;
	                a[i*n + j].y -= tmp_imag;
	            }
            }
            // PHASE TRANSFORMATION
            //q = -conj(a(k,k1)) / abs(a(k,k1));
            //w = sqrt(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            w = sqrtf(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            q.x = -a[k*n + k1].x / w;
            q.y =  a[k*n + k1].y / w;
            for(i=k1; i<m; i++){
                //a(i,k1) *= q;
                tmp_real  = a[i*n + k1].x * q.x;
                tmp_real -= a[i*n + k1].y * q.y;
                tmp_imag  = a[i*n + k1].x * q.y;
                tmp_imag += a[i*n + k1].y * q.x;
                a[i*n + k1].x = tmp_real;
                a[i*n + k1].y = tmp_imag;
            }
        }
        k = k1;
    } /* End of while(1) */

#if 0
    //デバック
    for(i=0; i<8; i++){
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[i][0].real, a[i][0].imag,
                a[i][1].real, a[i][1].imag,
                a[i][2].real, a[i][2].imag,
                a[i][3].real, a[i][3].imag,
                a[i][4].real, a[i][4].imag,
                a[i][5].real, a[i][5].imag,
                a[i][6].real, a[i][6].imag,
                a[i][7].real, a[i][7].imag);
    }
#endif

    // TOLERANCE FOR NEGLIGIBLE ELEMENTS
    eps = 0.0F;
    for(k=0; k<n; k++){
        s[k] = b[k];
        t[k] = c[k];
        if(s[k] + t[k] > eps){
            eps = s[k] + t[k];
        }
    }
    eps *= eta;
    //デバック
    //LOGI("eps = %g\n", eps);

    // INITIALIZATION OF u AND v
    if(nu > 0){
        //for(j=0; j<nu; j++){
            //for(i=0; i<m; i++){
        for(i=0; i<m; i++){
            for(j=0; j<nu; j++){
                //u(i,j) = std::complex<T>(0.0F, 0.0F);
                //u[i][j].real = 0.0f;
                //u[i][j].imag = 0.0f;
                u[i*n + j].x = 0.0f;
                u[i*n + j].y = 0.0f;
            }
            //u(j,j) = std::complex<T>(1.0F, 0.0F);
            //u[j][j].real = 1.0f; // skip because already set! u[j][j].imag = 0.0f;
            u[i*n + i].x = 1.0f; // swap loop i,j;
        }
    }

    if(nv > 0){
        //for(j=0; j<nv; j++){
            //for(i=0; i<n; i++){
        for(i=0; i<n; i++){
            for(j=0; j<nv; j++){
                //v(i,j) = std::complex<T>(0.0F, 0.0F);
                v[i*n + j].x = 0.0f;
                v[i*n + j].y = 0.0f;
            }
            //v(j,j) = std::complex<T>(1.0F, 0.0F);
            //v[j][j].real = 1.0f; // skip because already set! v[j][j].imag = 0.0f;
            v[i*n + i].x = 1.0f; // swap loop i,j;
        }
    }
    //QR DIAGONALIZATION
    for(k=nM1; k>=0; k--){
        //デバック
        //LOGI("k = %d\n", k);

        //TEST FOR SPLIT
        while(1){
            for(L=k; L>=0; L--){
                //デバック
	            //LOGI("%d : %g, %g, eps = %g\n", L, t[L], s[L-1], eps);
                if (ABS(t[L]) <= eps) goto Test;
                if(L > 0){
                    if (ABS(s[L - 1]) <= eps) break;
                }
            }

            //CANCELLATION OF E(L)
            cs = 0.0F;
            sn = 1.0F;
            L1 = L - 1;
            for(i=L; i<=k; i++){
                f = sn * t[i];
                t[i] *= cs;

                //デバック
                //LOGI("%d : %g <= %g ?\n", i, f, eps);

                if (ABS(f) <= eps) goto Test;

                h = s[i];
                //w = (float)sqrt(f * f + h * h);
                w = sqrtf(f * f + h * h);
                s[i] = w;
                //cs = h / w;
                //sn = -f / w;
                tmp = 1.0f / w;
                cs = h * tmp;
                sn = -f * tmp;

                if(nu > 0){
                    for(j=0; j<n; j++){
                        //x = real(u(j,L1));
                        //y = real(u(j,i));
                        x = u[j*n + L1].x;
                        y = u[j*n + i].x;

                        //u(j,L1) = std::complex<T>(x * cs + y * sn, 0.0F);
                        tmp  = x * cs;
                        tmp += y * sn;
                        u[j*n + L1].x = tmp;
                        u[j*n + L1].y = 0.0f;

                        //u(j,i) = std::complex<T>(y * cs - x * sn, 0.0F);
                        tmp  = y * cs;
                        tmp -= x * sn;
                        u[j*n + i].x = tmp;
                        u[j*n + i].y = 0.0f;
                    }
	            }

                if(np == n) continue;

                for(j=n; j<np; j++){
	                //q = a(L1,j);
	                //q = a[L1][j];
	                q = a[L1*n + j];
	                //r = a(i,j);
	                r = a[i*n + j];

	                //a(L1,j) = q * cs + r * sn;
	                tmp  = q.x * cs;
	                tmp += r.x * sn;
	                a[L1*n + j].x = tmp;
	                tmp  = q.y * cs;
	                tmp += r.y * sn;
	                a[L1*n + j].y = tmp;

	                //a(i,j) = r * cs - q * sn;
	                tmp  = r.x * cs;
	                tmp -= q.x * sn;
	                a[i*n + j].x = tmp;
	                tmp  = r.y * cs;
	                tmp -= q.y * sn;
	                a[i*n + j].y = tmp;
	            }
            }

            //TEST FOR CONVERGENCE
Test:       w = s[k];
            if (L == k) break;

            //ORIGIN SHIFT
            x = s[L];
            y = s[k - 1];
            g = t[k - 1];
            h = t[k];
            f = ((y - w) * (y + w) + (g - h) * (g + h)) / (2.0F * h * y);
            //g = (float)sqrt(f * f + 1.0F);
            g = sqrtf(f * f + 1.0F);
            if(f < 0.0F){ g = -g; }
            f = ((x - w) * (x + w) + (y / (f + g) - h) * h) / x;
  
            //QR STEP
            cs = 1.0F;
            sn = 1.0F;
            L1 = L + 1;
            for(i=L1; i<=k; i++){
                g = t[i];
                y = s[i];
                h = sn * g;
                g = cs * g;
                //w = (float)sqrt(h * h + f * f);
                w = sqrtf(h * h + f * f);
                t[i - 1] = w;
                //cs = f / w;
                //sn = h / w;
                tmp = 1.0f / w;
                cs = f * tmp;
                sn = h * tmp;
                f  = x * cs;
                f += g * sn;
                g  = g * cs;
                g -= x * sn;
                h  = y * sn;
                y  = y * cs;
                if(nv > 0){
	                for(j=0; j<n; j++){
                        //x = real(v(j,i - 1));
                        //w = real(v(j,i));
                        //x = v[j][i-1].real;
                        x = v[j*n + (i-1)].x;
                        w = v[j*n + i].x;

                        //v(j,i - 1) = std::complex<T>(x * cs + w * sn, 0.0F);
                        tmp  = x * cs;
                        tmp += w * sn;
                        //v[j][i-1].real = tmp;
                        //v[j][i-1].imag = 0.0f;
                        v[j*n + (i-1)].x = tmp;
                        v[j*n + (i-1)].y = 0.0f;
                        //v(j,i) = std::complex<T>(w * cs - x * sn, 0.0F);
                        tmp  = w * cs;
                        tmp -= x * sn;
                        v[j*n + i].x = tmp;
                        v[j*n + i].y = 0.0f;
                    }
                }
                //w = (float)sqrt(h * h + f * f);
                w = sqrtf(h * h + f * f);
                s[i - 1] = w;
                //cs = f / w;
                //sn = h / w;
                tmp = 1.0f / w;
                cs = f * tmp;
                sn = h * tmp;
                f = cs * g + sn * y;
                x = cs * y - sn * g;
                if(nu > 0){
                    for(j=0; j<n; j++){
                        //y = real(u(j,i - 1));
                        //w = real(u(j,i));
                        //y = u[j][i-1].real;
                        y = u[j*n + (i-1)].x;
                        w = u[j*n + i].x;

                        //u(j,i - 1) = std::complex<T>(y * cs + w * sn, 0.0F);
                        tmp  = y * cs;
                        tmp += w * sn;
                        //u[j][i-1].real = tmp;
                        //u[j][i-1].imag = 0.0f;
                        u[j*n +(i-1)].x = tmp;
                        u[j*n +(i-1)].y = 0.0f;
                        //u(j,i) = std::complex<T>(w * cs - y * sn, 0.0F);
                        tmp  = w * cs;
                        tmp -= y * sn;
                        u[j*n + i].x = tmp;
                        u[j*n + i].y = 0.0f;
                    }
                }

	            if (n == np) continue;

	            for(j=n; j<np; j++){
                    //q = a(i - 1,j);
                    //r = a(i,j);
                    q = a[(i-1)*n + j];
                    r = a[i*n + j];

                    //a(i - 1,j) = q * cs + r * sn;
                    tmp  = q.x * cs;
                    tmp += r.x * sn;
                    a[(i-1)*n + j].x = tmp;
                    tmp  = q.y * cs;
                    tmp += r.y * sn;
                    a[(i-1)*n + j].y = tmp;
                    //a(i,j) = r * cs - q * sn;
                    tmp  = r.x * cs;
                    tmp -= q.x * sn;
                    a[i*n + j].x = tmp;
                    tmp  = r.y * cs;
                    tmp -= q.y * sn;
                    a[i*n + j].y = tmp;
                }
            }
            t[L] = 0.0F;
            t[k] = f;
            s[k] = x;
       } /* End of while(1) */

        //CONVERGENCE
        if (w >= 0.0F) continue;

        s[k] = -w;

        if (nv == 0) continue;

        for(j=0; j<n; j++){
	        //v(j,k) = -v(j,k);
	        v[j*n + k].x = -v[j*n + k].x;
	        v[j*n + k].y = -v[j*n + k].y;
	    }
    }

    //SORT SINGULAR VALUES
    for(k=0; k<n; k++){	/* sort descending */
        g = -1.0F;
        j = k;
        for(i=k; i<n; i++){	/* sort descending */
            if (s[i] <= g) continue;

            g = s[i];
            j = i;
        }

        if (j == k) continue;

        s[j] = s[k];
        s[k] = g;
        if(nv > 0){
            for(i=0; i<n; i++){
                //q = v(i,j);
                //v(i,j) = v(i,k);
                //v(i,k) = q;

                //sugisaki
                //q = v[i][j];
                //v[i][j] = v[i][k];
                //v[i][k] = q;
                q.x = v[i*n + j].x;
                q.y = v[i*n + j].y;
                //v[i][j] = v[i][k];
                v[i*n + j] = v[i*n + k];
                v[i*n + k].x = q.x;
                v[i*n + k].y = q.y;
            }
        }

        if(nu > 0){
            for(i=0; i<n; i++){
                //q = u(i,j);
                //u(i,j) = u(i,k);
                //u(i,k) = q;

                //sugisaki
                //q = u[i][j];
                //u[i][j] = u[i][k];
                //u[i][k] = q;
                q.x = u[i*n + j].x;
                q.y = u[i*n + j].y;
                //u[i][j] = u[i][k];
                u[i*n + j] = u[i*n + k];
                u[i*n + k].x = q.x;
                u[i*n + k].y = q.y;
            }
        }

        if(n == np) continue;

        for(i=n; i<np; i++){
            //q = a(j,i);
            //a(j,i) = a(k,i);
            //a(k,i) = q;
            q = a[j*n + i];
            a[j*n + i] = a[k*n + i];
            a[k*n + i] = q;
        }
    }

    //BACK TRANSFORMATION
    if(nu > 0){
        for(k=nM1; k>=0; k--){
            if (b[k] == 0.0F) continue;

            //w = sqrt(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);
            w = sqrtf(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);
            //q = -a(k,k) / abs(a(k,k));
            //q.x = -a[k*n + k].x / w;
            //q.y = -a[k*n + k].y / w;
            tmp2 = 1.0f / (w * b[k]);
            tmp = 1.0f / w;
            q.x = -a[k*n + k].x * tmp;
            q.y = -a[k*n + k].y * tmp;

            for(j=0; j<nu; j++){
                //u(k,j) *= q;
                tmp_real  = u[k*n + j].x * q.x;
                tmp_real -= u[k*n + j].y * q.y;
                tmp_imag  = u[k*n + j].x * q.y;
                tmp_imag += u[k*n + j].y * q.x;
                u[k*n + j].x = tmp_real;
                u[k*n + j].y = tmp_imag;
            }

            for(j=0; j<nu; j++){
                //q = std::complex<T>(0.0F, 0.0F);
                q.x = 0.0f;
                q.y = 0.0f;
                for(i=k; i<m; i++){
                    //q += conj(a(i,k)) * u(i,j);
                    q.x += a[i*n + k].x * u[i*n + j].x;
                    q.x += a[i*n + k].y * u[i*n + j].y;
                    q.y += a[i*n + k].x * u[i*n + j].y;
                    q.y -= a[i*n + k].y * u[i*n + j].x;
                }

                //w = sqrt(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);
                //w = sqrtf(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y); // このループ内でaは更新しないので不要
                //q /= abs(a(k,k)) * b[k];
                //q.x = q.x / (w * b[k]);
                //q.y = q.y / (w * b[k]);
                q.x = q.x * tmp2;
                q.y = q.y * tmp2;

                for(i=k; i<m; i++){
                    //u(i,j) -= q * a(i,k);
                    tmp  = q.x * a[i*n + k].x;
                    tmp -= q.y * a[i*n + k].y;
                    u[i*n + j].x -= tmp;
                    tmp  = q.x * a[i*n + k].y;
                    tmp += q.y * a[i*n + k].x;
                    u[i*n + j].y -= tmp;
                }
            }
        }
    }

    if(nv > 0 && n > 1){
        for(k=n-2; k>=0; k--){
            k1 = k + 1;
            if (c[k1] == 0.0F) continue;

            //w = sqrt(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            w = sqrtf(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            //q = -conj(a(k,k1)) / abs(a(k,k1));
            //q.x = -a[k*n + k1].x / w;
            //q.y =  a[k*n + k1].y / w;
            tmp2 = 1.0f / (w * c[k1]);
            tmp = 1.0f / w;
            q.x = -a[k*n + k1].x * tmp;
            q.y =  a[k*n + k1].y * tmp;

            for(j=0; j<nv; j++){
                //v(k1,j) *= q;
                //tmp_real  = v[k1][j].real * q.x;
                //tmp_real -= v[k1][j].imag * q.y;
                //tmp_imag  = v[k1][j].real * q.y;
                //tmp_imag += v[k1][j].imag * q.x;
                tmp_real  = v[k1*n + j].x * q.x;
                tmp_real -= v[k1*n + j].y * q.y;
                tmp_imag  = v[k1*n + j].x * q.y;
                tmp_imag += v[k1*n + j].y * q.x;
                //v[k1][j].real = tmp_real;
                //v[k1][j].imag = tmp_imag;
                v[k1*n + j].x = tmp_real;
                v[k1*n + j].y = tmp_imag;
            }

            for(j=0; j<nv; j++){
                //q = std::complex<T>(0.0F, 0.0F);
                q.x = 0.0f;
                q.y = 0.0f;

                for(i=k1; i<n; i++){
                    //q += a(k,i) * v(i,j);
                    q.x += a[k*n + i].x * v[i*n + j].x;
                    q.x -= a[k*n + i].y * v[i*n + j].y;
                    q.y += a[k*n + i].x * v[i*n + j].y;
                    q.y += a[k*n + i].y * v[i*n + j].x;
                }

                //w = sqrt(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
                //w = sqrtf(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y); // このループ内でaは更新しないので不要
                //q = q / (abs(a(k,k1)) * c[k1]);
                //q.x = q.x / (w * c[k1]);
                //q.y = q.y / (w * c[k1]);
                q.x = q.x * tmp2;
                q.y = q.y * tmp2;

                for(i=k1; i<n; i++){
                    //v(i,j) -= q * conj(a(k,i));
                    tmp  =  q.x * a[k*n + i].x;
                    tmp +=  q.y * a[k*n + i].y;
                    v[i*n + j].x -= tmp;
                    tmp  = -q.x * a[k*n + i].y;
                    tmp +=  q.y * a[k*n + i].x;
                    v[i*n + j].y -= tmp;
                }
            }
        }

    } //if(nv > 0 && n > 1)

    } //for(k=0; k<pslength; k++)

}

//void cpu_Svd1(cuComplex *aa, float *ss, cuComplex *uu, cuComplex *vv,
//    int m, int n,
//    int *UsesFreq, int pslength,
//    float *bb, float *cc, float *tt
//    )
void cpu_Svd1(cuComplex *aa, int m, int n,
    int *UsesFreq, int pslength,
    float *bb, float *cc
    )
{
    //int m;
    //int n;
    int p;  // transformation Conj(Tran(u)) is applied to the p vectors given in columns n, n+1, ..., n+p-1 of matrix a
    //int nu; // considered number of cols of u
    //int nv; // considered number of cols of v

    //float b[16];
    //float c[16];
    //float t[16];
    float *b;
    float *c;
    //float *t;

    //COMPLEX_FLOAT q;
    cuComplex q;
    //COMPLEX_FLOAT r;
    //cuComplex r;
    //int i, j, k, k1, L, L1, nM1, np;
    int i, j, k, k1, nM1, np;

    //float cs, eps, eta, f, g, h;
    //float sn;
    //float tol, w, x, y, z;
    float tol, w, z;
    //float tmp, tmp2, tmp_real, tmp_imag;
    float tmp, tmp_real, tmp_imag;
    //float f_real;
    //float f_imag;

    int kk;
    cuComplex *a;
    //float *s;
    //cuComplex *u;
    //cuComplex *v;

    for(kk=0; kk<pslength; kk++){
        if(!UsesFreq[kk]){
            continue;
        }

        a = &aa[kk*m*n];
        //s = &ss[kk*n]; //m or n?
        //u = &uu[kk*m*n];
        //v = &vv[kk*m*n];

        b = &bb[kk*MAX_CH_NUM];
        c = &cc[kk*MAX_CH_NUM];
        //t = &tt[kk*MAX_CH_NUM];

//----------------------------------------------------------------
    //m = amatrix_info.mic_num;
    //n = amatrix_info.mic_num;
    //m = localize_music_info.tf_channel_num;
    //n = localize_music_info.tf_channel_num;

	//以下３つはconst
    p = 0;
    //nu = m;
    //nv = n;
    
	//以下4つはconst
    //eta = 1.5E-07F;
    tol = 1.5E-31F;
    np  = n + p;
    nM1 = n - 1;

    //Lは最初の関数は未使用
    //L   = 0;  //loop変数

    //以下２つは最初の関数だけ行う
    // HOUSEHOLDER REDUCTION
    c[0] = 0.0F;
    k = 0; // TOLERANCE FOR NEGLIGIBLE ELEMENTS後(while loop)は初期化される
    
    //デバック
    //LOGI("(%f, %f), (%f, %f)\n", a[0][0].real, a[0][0].imag, a[0][1].real, a[0][1].imag);

    while(1){
        k1 = k + 1;
        // ELIMINATION OF a(i,k), i = k, ..., m-1
        z = 0.0F;

        for(i = k; i < m; i++){
            //z += norm(a(i,k));
            //z += a[i][k].real * a[i][k].real;
            //z += a[i][k].imag * a[i][k].imag;
            z += a[i*n + k].x * a[i*n + k].x;
            z += a[i*n + k].y * a[i*n + k].y;
        }
        //デバック
        //LOGI("%d : %g\n", k, z);

        b[k] = 0.0F;
        if(z > tol){
            //z = (float)sqrt(z);
            z = sqrtf(z);
            b[k] = z;

            //w = abs(a(k,k));
            //w = sqrt(a[k][k].real * a[k][k].real + a[k][k].imag * a[k][k].imag);
            //w = sqrtf(a[k][k].real * a[k][k].real + a[k][k].imag * a[k][k].imag);
            w = sqrtf(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);

            if(w != 0.0F){
                //q = a(k,k) / w;
                //q.real = a[k][k].real / w;
                //q.y = a[k][k].imag / w;
                tmp = 1.0f / w;
                //q.real = a[k][k].real * tmp;
                //q.y = a[k][k].imag * tmp;
                q.x = a[k*n + k].x * tmp;
                q.y = a[k*n + k].y * tmp;
            }
            else{
                q.x = 1.0f;
                q.y = 0.0f;
            }
            //a(k,k) = q * (z + w);
            //a[k][k].real = q.real * (z + w);
            //a[k][k].imag = q.y * (z + w);
            tmp = (z + w);
            //a[k][k].real = q.real * tmp;
            //a[k][k].imag = q.y * tmp;
            a[k*n + k].x = q.x * tmp;
            a[k*n + k].y = q.y * tmp;
            tmp = 1.0f / (tmp * z);

            if(k != np - 1){
                for(j=k1; j<np; j++){
                    //q = std::complex<T>(0.0F, 0.0F);
                    q.x = 0.0f;
                    q.y = 0.0f;

                    for (i=k; i<m; i++){
                        //q += conj(a(i,k)) * a(i,j);
                        //q.x += a[i][k].real * a[i][j].real;
                        //q.x += a[i][k].imag * a[i][j].imag;
                        //q.y += a[i][k].real * a[i][j].imag;
                        //q.y -= a[i][k].imag * a[i][j].real;
                        q.x += a[i*n + k].x * a[i*n + j].x;
                        q.x += a[i*n + k].y * a[i*n + j].y;
                        q.y += a[i*n + k].x * a[i*n + j].y;
                        q.y -= a[i*n + k].y * a[i*n + j].x;
                    }

                    //q /= z * (z + w);
                    ////q.x = q.x / (z * (z + w));
                    ////q.y = q.y / (z * (z + w));
                    q.x *= tmp;
                    q.y *= tmp;
                    for(i=k; i<m; i++){
                        //a(i,j) -= q * a(i,k);
                        //tmp_real  = q.x * a[i][k].real;
                        //tmp_real -= q.y * a[i][k].imag;
                        //tmp_imag  = q.x * a[i][k].imag;
                        //tmp_imag += q.y * a[i][k].real;
                        tmp_real  = q.x * a[i*n + k].x;
                        tmp_real -= q.y * a[i*n + k].y;
                        tmp_imag  = q.x * a[i*n + k].y;
                        tmp_imag += q.y * a[i*n + k].x;
                        //a[i][j].real -= tmp_real;
                        //a[i][j].imag -= tmp_imag;
                        a[i*n + j].x -= tmp_real;
                        a[i*n + j].y -= tmp_imag;
                    }
                }
            }
            // PHASE TRANSFORMATION
            //q = -conj(a(k,k)) / abs(a(k,k));
            //w = sqrt(a[k][k].real * a[k][k].real + a[k][k].imag * a[k][k].imag);
            //w = sqrtf(a[k][k].real * a[k][k].real + a[k][k].imag * a[k][k].imag);
            w = sqrtf(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);
            //q.x = -a[k][k].real / w;
            //q.y =  a[k][k].imag / w;
            tmp = 1.0f / w;
            //q.x = -a[k][k].real * tmp;
            //q.y =  a[k][k].imag * tmp;
            q.x = -a[k*n + k].x * tmp;
            q.y =  a[k*n + k].y * tmp;

            //デバック
            //LOGI("q = (%g,%g)\n", q.x, q.y);

            for(j=k1; j<np; j++){
                //a(k,j) *= q;
                //tmp_real  = a[k][j].real * q.x;
                //tmp_real -= a[k][j].imag * q.y;
                //tmp_imag  = a[k][j].real * q.y;
                //tmp_imag += a[k][j].imag * q.x;
                tmp_real  = a[k*n + j].x * q.x;
                tmp_real -= a[k*n + j].y * q.y;
                tmp_imag  = a[k*n + j].x * q.y;
                tmp_imag += a[k*n + j].y * q.x;
                //a[k][j].real = tmp_real;
                //a[k][j].imag = tmp_imag;
                a[k*n + j].x = tmp_real;
                a[k*n + j].y = tmp_imag;
            }
        }
#if 0
        //デバック
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[0][0].real, a[0][0].imag,
                a[0][1].real, a[0][1].imag,
                a[0][2].real, a[0][2].imag,
                a[0][3].real, a[0][3].imag);
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[1][0].real, a[1][0].imag,
                a[1][1].real, a[1][1].imag,
                a[1][2].real, a[1][2].imag,
                a[1][3].real, a[1][3].imag);
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[2][0].real, a[2][0].imag,
                a[2][1].real, a[2][1].imag,
                a[2][2].real, a[2][2].imag,
                a[2][3].real, a[2][3].imag);
#endif
        // ELIMINATION OF a(k][j], j = k+2, ..., n-1
        if (k == nM1) break;

        z = 0.0F;
        for(j=k1; j<n; j++){
            //z += norm(a(k,j));
            z += a[k*n + j].x * a[k*n + j].x;
            z += a[k*n + j].y * a[k*n + j].y;
        }

        c[k1] = 0.0F;
        if(z > tol){
            //z = (float)sqrt(z);
            z = sqrtf(z);
            c[k1] = z;

            //w = abs(a(k,k1));
            //w = sqrt(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            w = sqrtf(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);

            if(w != 0.0F){
                //q = a(k,k1) / w;
                //q.x = a[k*n + k1].x / w;
                //q.y = a[k*n + k1].y / w;
                tmp = 1.0f / w;
                q.x = a[k*n + k1].x * tmp;
                q.y = a[k*n + k1].y * tmp;
            }
            else{
                q.x = 1.0f;
                q.y = 0.0f;
            }
            //a(k,k1) = q * (z + w);
            tmp = (z + w);
            ////a[k*n + k1].x = q.x * (z + w);
            ////a[k*n + k1].y = q.y * (z + w);
            a[k*n + k1].x = q.x * tmp;
            a[k*n + k1].y = q.y * tmp;
            tmp = 1.0f / (tmp * z);

            for(i=k1; i<m; i++){
                //q = std::complex<T>(0.0F, 0.0F);
                q.x = 0.0f;
                q.y = 0.0f;

                for(j=k1; j<n; j++){
                    //q += conj(a(k,j)) * a(i,j);
                    q.x += a[k*n + j].x * a[i*n + j].x;
                    q.x += a[k*n + j].y * a[i*n + j].y;
                    q.y += a[k*n + j].x * a[i*n + j].y;
                    q.y -= a[k*n + j].y * a[i*n + j].x;
                }

                //q /= z * (z + w);
                ////q.x = q.x / (z * (z + w));
                ////q.y = q.y / (z * (z + w));
                q.x *= tmp;
                q.y *= tmp;
                for(j=k1; j<n; j++){
                    //a(i,j) -= q * a(k,j);
                    tmp_real  = q.x * a[k*n + j].x;
                    tmp_real -= q.y * a[k*n + j].y;
                    tmp_imag  = q.x * a[k*n + j].y;
                    tmp_imag += q.y * a[k*n + j].x;
                    a[i*n + j].x -= tmp_real;
                    a[i*n + j].y -= tmp_imag;
                }
            }
            // PHASE TRANSFORMATION
            //q = -conj(a(k,k1)) / abs(a(k,k1));
            //w = sqrt(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            w = sqrtf(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            q.x = -a[k*n + k1].x / w;
            q.y =  a[k*n + k1].y / w;

            for(i=k1; i<m; i++){
                //a(i,k1) *= q;
                tmp_real  = a[i*n + k1].x * q.x;
                tmp_real -= a[i*n + k1].y * q.y;
                tmp_imag  = a[i*n + k1].x * q.y;
                tmp_imag += a[i*n + k1].y * q.x;
                a[i*n + k1].x = tmp_real;
                a[i*n + k1].y = tmp_imag;
            }
        }
        k = k1;
    } /* End of while(1) */

#if 0
    //デバック
    for(i=0; i<8; i++){
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[i][0].real, a[i][0].imag,
                a[i][1].real, a[i][1].imag,
                a[i][2].real, a[i][2].imag,
                a[i][3].real, a[i][3].imag,
                a[i][4].real, a[i][4].imag,
                a[i][5].real, a[i][5].imag,
                a[i][6].real, a[i][6].imag,
                a[i][7].real, a[i][7].imag);
    }
#endif

    } //for(k=0; k<pslength; k++)
}


__global__
void gpu_Svd1(cuComplex *aa, int m, int n,
    int *UsesFreq, int pslength,
    float *bb, float *cc
    )
{
    int p;  // transformation Conj(Tran(u)) is applied to the p vectors given in columns n, n+1, ..., n+p-1 of matrix a
    float *b;
    float *c;
    
    cuComplex q;
    int i, j, k, k1, nM1, np;
    
    float tol, w, z;
    float tmp, tmp_real, tmp_imag;

    int kk;
    cuComplex *a;

    kk = blockIdx.x;

    //for(kk=0; kk<pslength; kk++){

    if(!UsesFreq[kk]){
        //continue;
        return;
    }

    a = &aa[kk*m*n];
    b = &bb[kk*MAX_CH_NUM];
    c = &cc[kk*MAX_CH_NUM];

//----------------------------------------------------------------
    //以下３つはconst
    p = 0;

    //以下4つはconst
    tol = 1.5E-31F;
    np  = n + p;
    nM1 = n - 1;

    //以下２つは最初の関数だけ行う
    // HOUSEHOLDER REDUCTION
    c[0] = 0.0F;
    k = 0; // TOLERANCE FOR NEGLIGIBLE ELEMENTS後(while loop)は初期化される

    //デバック
    //LOGI("(%f, %f), (%f, %f)\n", a[0][0].real, a[0][0].imag, a[0][1].real, a[0][1].imag);

    while(1){
        k1 = k + 1;
        // ELIMINATION OF a(i,k), i = k, ..., m-1
        z = 0.0F;
        
        for(i = k; i < m; i++){
            //z += norm(a(i,k));
            //z += a[i][k].real * a[i][k].real;
            //z += a[i][k].imag * a[i][k].imag;
            z += a[i*n + k].x * a[i*n + k].x;
            z += a[i*n + k].y * a[i*n + k].y;
        }
        //デバック
        //LOGI("%d : %g\n", k, z);

        b[k] = 0.0F;
        if(z > tol){
            //z = (float)sqrt(z);
            z = sqrtf(z);
            b[k] = z;

            //w = abs(a(k,k));
            //w = sqrt(a[k][k].real * a[k][k].real + a[k][k].imag * a[k][k].imag);
            //w = sqrtf(a[k][k].real * a[k][k].real + a[k][k].imag * a[k][k].imag);
            w = sqrtf(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);

            if(w != 0.0F){
                //q = a(k,k) / w;
                //q.real = a[k][k].real / w;
                //q.y = a[k][k].imag / w;
                tmp = 1.0f / w;
                //q.real = a[k][k].real * tmp;
                //q.y = a[k][k].imag * tmp;
                q.x = a[k*n + k].x * tmp;
                q.y = a[k*n + k].y * tmp;
            }
            else{
                q.x = 1.0f;
                q.y = 0.0f;
            }
            //a(k,k) = q * (z + w);
            //a[k][k].real = q.real * (z + w);
            //a[k][k].imag = q.y * (z + w);
            tmp = (z + w);
            //a[k][k].real = q.real * tmp;
            //a[k][k].imag = q.y * tmp;
            a[k*n + k].x = q.x * tmp;
            a[k*n + k].y = q.y * tmp;
            tmp = 1.0f / (tmp * z);

            if(k != np - 1){
                for(j=k1; j<np; j++){
                    //q = std::complex<T>(0.0F, 0.0F);
                    q.x = 0.0f;
                    q.y = 0.0f;

                    for (i=k; i<m; i++){
                        //q += conj(a(i,k)) * a(i,j);
                        q.x += a[i*n + k].x * a[i*n + j].x;
                        q.x += a[i*n + k].y * a[i*n + j].y;
                        q.y += a[i*n + k].x * a[i*n + j].y;
                        q.y -= a[i*n + k].y * a[i*n + j].x;
                    }

                    //q /= z * (z + w);
                    ////q.x = q.x / (z * (z + w));
                    ////q.y = q.y / (z * (z + w));
                    q.x *= tmp;
                    q.y *= tmp;
                    for(i=k; i<m; i++){
                        //a(i,j) -= q * a(i,k);
                        tmp_real  = q.x * a[i*n + k].x;
                        tmp_real -= q.y * a[i*n + k].y;
                        tmp_imag  = q.x * a[i*n + k].y;
                        tmp_imag += q.y * a[i*n + k].x;
                        //a[i][j].real -= tmp_real;
                        //a[i][j].imag -= tmp_imag;
                        a[i*n + j].x -= tmp_real;
                        a[i*n + j].y -= tmp_imag;
                    }
                }
            }
            // PHASE TRANSFORMATION
            //q = -conj(a(k,k)) / abs(a(k,k));
            //w = sqrt(a[k][k].real * a[k][k].real + a[k][k].imag * a[k][k].imag);
            //w = sqrtf(a[k][k].real * a[k][k].real + a[k][k].imag * a[k][k].imag);
            w = sqrtf(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);
            //q.x = -a[k][k].real / w;
            //q.y =  a[k][k].imag / w;
            tmp = 1.0f / w;
            //q.x = -a[k][k].real * tmp;
            //q.y =  a[k][k].imag * tmp;
            q.x = -a[k*n + k].x * tmp;
            q.y =  a[k*n + k].y * tmp;

            //デバック
            //LOGI("q = (%g,%g)\n", q.x, q.y);

            for(j=k1; j<np; j++){
                //a(k,j) *= q;
                tmp_real  = a[k*n + j].x * q.x;
                tmp_real -= a[k*n + j].y * q.y;
                tmp_imag  = a[k*n + j].x * q.y;
                tmp_imag += a[k*n + j].y * q.x;
                a[k*n + j].x = tmp_real;
                a[k*n + j].y = tmp_imag;
            }
        }
#if 0
        //デバック
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[0][0].real, a[0][0].imag,
                a[0][1].real, a[0][1].imag,
                a[0][2].real, a[0][2].imag,
                a[0][3].real, a[0][3].imag);
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[1][0].real, a[1][0].imag,
                a[1][1].real, a[1][1].imag,
                a[1][2].real, a[1][2].imag,
                a[1][3].real, a[1][3].imag);
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[2][0].real, a[2][0].imag,
                a[2][1].real, a[2][1].imag,
                a[2][2].real, a[2][2].imag,
                a[2][3].real, a[2][3].imag);
#endif
        // ELIMINATION OF a(k][j], j = k+2, ..., n-1
        if (k == nM1) break;

        z = 0.0F;
        for(j=k1; j<n; j++){
            //z += norm(a(k,j));
            z += a[k*n + j].x * a[k*n + j].x;
            z += a[k*n + j].y * a[k*n + j].y;
        }

        c[k1] = 0.0F;
        if(z > tol){
            //z = (float)sqrt(z);
            z = sqrtf(z);
            c[k1] = z;

            //w = abs(a(k,k1));
            //w = sqrt(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            w = sqrtf(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);

            if(w != 0.0F){
                //q = a(k,k1) / w;
                //q.x = a[k*n + k1].x / w;
                //q.y = a[k*n + k1].y / w;
                tmp = 1.0f / w;
                q.x = a[k*n + k1].x * tmp;
                q.y = a[k*n + k1].y * tmp;
            }
            else{
                q.x = 1.0f;
                q.y = 0.0f;
            }
            //a(k,k1) = q * (z + w);
            tmp = (z + w);
            ////a[k*n + k1].x = q.x * (z + w);
            ////a[k*n + k1].y = q.y * (z + w);
            a[k*n + k1].x = q.x * tmp;
            a[k*n + k1].y = q.y * tmp;
            tmp = 1.0f / (tmp * z);

            for(i=k1; i<m; i++){
                //q = std::complex<T>(0.0F, 0.0F);
                q.x = 0.0f;
                q.y = 0.0f;

                for(j=k1; j<n; j++){
                    //q += conj(a(k,j)) * a(i,j);
                    q.x += a[k*n + j].x * a[i*n + j].x;
                    q.x += a[k*n + j].y * a[i*n + j].y;
                    q.y += a[k*n + j].x * a[i*n + j].y;
                    q.y -= a[k*n + j].y * a[i*n + j].x;
                }

                //q /= z * (z + w);
                ////q.x = q.x / (z * (z + w));
                ////q.y = q.y / (z * (z + w));
                q.x *= tmp;
                q.y *= tmp;
                for(j=k1; j<n; j++){
                    //a(i,j) -= q * a(k,j);
                    tmp_real  = q.x * a[k*n + j].x;
                    tmp_real -= q.y * a[k*n + j].y;
                    tmp_imag  = q.x * a[k*n + j].y;
                    tmp_imag += q.y * a[k*n + j].x;
                    a[i*n + j].x -= tmp_real;
                    a[i*n + j].y -= tmp_imag;
                }
            }
            // PHASE TRANSFORMATION
            //q = -conj(a(k,k1)) / abs(a(k,k1));
            //w = sqrt(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            w = sqrtf(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            q.x = -a[k*n + k1].x / w;
            q.y =  a[k*n + k1].y / w;

            for(i=k1; i<m; i++){
                //a(i,k1) *= q;
                tmp_real  = a[i*n + k1].x * q.x;
                tmp_real -= a[i*n + k1].y * q.y;
                tmp_imag  = a[i*n + k1].x * q.y;
                tmp_imag += a[i*n + k1].y * q.x;
                a[i*n + k1].x = tmp_real;
                a[i*n + k1].y = tmp_imag;
            }
        }
        k = k1;
    } /* End of while(1) */

#if 0
    //デバック
    for(i=0; i<8; i++){
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[i][0].real, a[i][0].imag,
                a[i][1].real, a[i][1].imag,
                a[i][2].real, a[i][2].imag,
                a[i][3].real, a[i][3].imag,
                a[i][4].real, a[i][4].imag,
                a[i][5].real, a[i][5].imag,
                a[i][6].real, a[i][6].imag,
                a[i][7].real, a[i][7].imag);
    }
#endif

    //} //for(k=0; k<pslength; k++)
}


__global__
void gpu_Svd1_1(cuComplex *aa, int m, int n,
    int *UsesFreq, int pslength,
    float *bb, float *cc,
    const int st_freq
    )
{
    int p;  // transformation Conj(Tran(u)) is applied to the p vectors given in columns n, n+1, ..., n+p-1 of matrix a
    float *b;
    float *c;
    
    cuComplex q;
    int i, j, k, k1, nM1, np;
    
    float tol, w, z;
    float tmp, tmp_real, tmp_imag;

    int kk;
    cuComplex *a;

    //kk = blockIdx.x;
    //kk = threadIdx.x;
    kk = blockIdx.x + st_freq;

    //for(kk=0; kk<pslength; kk++){

    //if(!UsesFreq[kk]){
    //        //continue;
    //        return;
    //}

    a = &aa[kk*m*n];
    b = &bb[kk*MAX_CH_NUM];
    c = &cc[kk*MAX_CH_NUM];

//----------------------------------------------------------------
    //以下３つはconst
    p = 0;

    //以下4つはconst
    tol = 1.5E-31F;
    np  = n + p;
    nM1 = n - 1;

    //以下２つは最初の関数だけ行う
    // HOUSEHOLDER REDUCTION
    c[0] = 0.0F;
    k = 0; // TOLERANCE FOR NEGLIGIBLE ELEMENTS後(while loop)は初期化される

    //デバック
    //LOGI("(%f, %f), (%f, %f)\n", a[0][0].real, a[0][0].imag, a[0][1].real, a[0][1].imag);

    cuComplex tmp_a;

    while(1){
        k1 = k + 1;
        // ELIMINATION OF a(i,k), i = k, ..., m-1
        z = 0.0F;

        for(i = k; i < m; i++){
            //z += norm(a(i,k));
            //z += a[i][k].real * a[i][k].real;
            //z += a[i][k].imag * a[i][k].imag;
#if 0
            z += a[i*n + k].x * a[i*n + k].x;
            z += a[i*n + k].y * a[i*n + k].y;
#else
            tmp_a = a[i*n + k];
            //z += tmp_a.x*tmp_a.x + tmp_a.y*tmp_a.y;
            z += tmp_a.x * tmp_a.x;
            z += tmp_a.y * tmp_a.y;
#endif
        }
        //デバック
        //LOGI("%d : %g\n", k, z);

        b[k] = 0.0F;

        if(z > tol){
            //z = (float)sqrt(z);
            z = sqrtf(z);
            b[k] = z;

            //w = abs(a(k,k));
            //w = sqrt(a[k][k].real * a[k][k].real + a[k][k].imag * a[k][k].imag);
            //w = sqrtf(a[k][k].real * a[k][k].real + a[k][k].imag * a[k][k].imag);
            //w = sqrtf(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);
            tmp_a = a[k*n + k];
            w = sqrtf(tmp_a.x * tmp_a.x + tmp_a.y * tmp_a.y);

            if(w != 0.0F){
                //q = a(k,k) / w;
                //q.real = a[k][k].real / w;
                //q.y = a[k][k].imag / w;
                tmp = 1.0f / w;
                //q.real = a[k][k].real * tmp;
                //q.y = a[k][k].imag * tmp;
                //q.x = a[k*n + k].x * tmp;
                //q.y = a[k*n + k].y * tmp;
                q.x = tmp_a.x * tmp;
                q.y = tmp_a.y * tmp;
            }
            else{
                q.x = 1.0f;
                q.y = 0.0f;
            }
            //a(k,k) = q * (z + w);
            //a[k][k].real = q.real * (z + w);
            //a[k][k].imag = q.y * (z + w);
            tmp = (z + w);
            //a[k][k].real = q.real * tmp;
            //a[k][k].imag = q.y * tmp;
            //a[k*n + k].x = q.x * tmp;
            //a[k*n + k].y = q.y * tmp;
            tmp_a.x = q.x * tmp;
            tmp_a.y = q.y * tmp;
            a[k*n + k] = tmp_a;
            tmp = 1.0f / (tmp * z);

            cuComplex tmp_i_k;
            cuComplex tmp_i_j;

            if(k != np - 1){
                for(j=k1; j<np; j++){
                    //q = std::complex<T>(0.0F, 0.0F);
                    q.x = 0.0f;
                    q.y = 0.0f;
                    
                    for (i=k; i<m; i++){
                        //q += conj(a(i,k)) * a(i,j);
                        //q.x += a[i*n + k].x * a[i*n + j].x;
                        //q.x += a[i*n + k].y * a[i*n + j].y;
                        //q.y += a[i*n + k].x * a[i*n + j].y;
                        //q.y -= a[i*n + k].y * a[i*n + j].x;
                        tmp_i_k = a[i*n + k];
                        tmp_i_j = a[i*n + j];
                        q.x += tmp_i_k.x * tmp_i_j.x;
                        q.x += tmp_i_k.y * tmp_i_j.y;
                        q.y += tmp_i_k.x * tmp_i_j.y;
                        q.y -= tmp_i_k.y * tmp_i_j.x;
                    }

                    //q /= z * (z + w);
                    ////q.x = q.x / (z * (z + w));
                    ////q.y = q.y / (z * (z + w));
                    q.x *= tmp;
                    q.y *= tmp;
                    for(i=k; i<m; i++){
                        //a(i,j) -= q * a(i,k);
                        //tmp_real  = q.x * a[i*n + k].x;
                        //tmp_real -= q.y * a[i*n + k].y;
                        //tmp_imag  = q.x * a[i*n + k].y;
                        //tmp_imag += q.y * a[i*n + k].x;
                        tmp_i_k = a[i*n + k];
                        tmp_real  = q.x * tmp_i_k.x;
                        tmp_real -= q.y * tmp_i_k.y;
                        tmp_imag  = q.x * tmp_i_k.y;
                        tmp_imag += q.y * tmp_i_k.x;
                        //a[i][j].real -= tmp_real;
                        //a[i][j].imag -= tmp_imag;
                        a[i*n + j].x -= tmp_real;
                        a[i*n + j].y -= tmp_imag;
                    }
                }
            }
            // PHASE TRANSFORMATION
            //q = -conj(a(k,k)) / abs(a(k,k));
            //w = sqrt(a[k][k].real * a[k][k].real + a[k][k].imag * a[k][k].imag);
            //w = sqrtf(a[k][k].real * a[k][k].real + a[k][k].imag * a[k][k].imag);
            //w = sqrtf(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);
            tmp_a = a[k*n + k];
            w = sqrtf(tmp_a.x * tmp_a.x + tmp_a.y * tmp_a.y);
            //q.x = -a[k][k].real / w;
            //q.y =  a[k][k].imag / w;
            tmp = 1.0f / w;
            //q.x = -a[k][k].real * tmp;
            //q.y =  a[k][k].imag * tmp;
            //q.x = -a[k*n + k].x * tmp;
            //q.y =  a[k*n + k].y * tmp;
            q.x = -tmp_a.x * tmp;
            q.y =  tmp_a.y * tmp;

            //デバック
            //LOGI("q = (%g,%g)\n", q.x, q.y);

            cuComplex tmp_k_j;

            for(j=k1; j<np; j++){
                //a(k,j) *= q;
                //tmp_real  = a[k*n + j].x * q.x;
                //tmp_real -= a[k*n + j].y * q.y;
                //tmp_imag  = a[k*n + j].x * q.y;
                //tmp_imag += a[k*n + j].y * q.x;
                tmp_k_j = a[k*n + j];
                tmp_a.x  = tmp_k_j.x * q.x;
                tmp_a.x -= tmp_k_j.y * q.y;
                tmp_a.y  = tmp_k_j.x * q.y;
                tmp_a.y += tmp_k_j.y * q.x;
                //a[k*n + j].x = tmp_real;
                //a[k*n + j].y = tmp_imag;
                a[k*n + j] = tmp_a;
            }
        }
#if 0
        //デバック
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[0][0].real, a[0][0].imag,
                a[0][1].real, a[0][1].imag,
                a[0][2].real, a[0][2].imag,
                a[0][3].real, a[0][3].imag);
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[1][0].real, a[1][0].imag,
                a[1][1].real, a[1][1].imag,
                a[1][2].real, a[1][2].imag,
                a[1][3].real, a[1][3].imag);
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[2][0].real, a[2][0].imag,
                a[2][1].real, a[2][1].imag,
                a[2][2].real, a[2][2].imag,
                a[2][3].real, a[2][3].imag);
#endif
        // ELIMINATION OF a(k][j], j = k+2, ..., n-1
        if (k == nM1) break;

        z = 0.0F;

        for(j=k1; j<n; j++){
            //z += norm(a(k,j));
            //z += a[k*n + j].x * a[k*n + j].x;
            //z += a[k*n + j].y * a[k*n + j].y;
            tmp_a = a[k*n + j];
            z += tmp_a.x * tmp_a.x;
            z += tmp_a.y * tmp_a.y;
        }

        c[k1] = 0.0F;

        if(z > tol){
            //z = (float)sqrt(z);
            z = sqrtf(z);
            c[k1] = z;

            //w = abs(a(k,k1));
            //w = sqrt(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            //w = sqrtf(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            tmp_a = a[k*n + k1];
            w = sqrtf(tmp_a.x * tmp_a.x + tmp_a.y * tmp_a.y);

            if(w != 0.0F){
                //q = a(k,k1) / w;
                //q.x = a[k*n + k1].x / w;
                //q.y = a[k*n + k1].y / w;
                tmp = 1.0f / w;
                //q.x = a[k*n + k1].x * tmp;
                //q.y = a[k*n + k1].y * tmp;
                q.x = tmp_a.x * tmp;
                q.y = tmp_a.y * tmp;
            }
            else{
                q.x = 1.0f;
                q.y = 0.0f;
            }
            //a(k,k1) = q * (z + w);
            tmp = (z + w);
            ////a[k*n + k1].x = q.x * (z + w);
            ////a[k*n + k1].y = q.y * (z + w);
            //a[k*n + k1].x = q.x * tmp;
            //a[k*n + k1].y = q.y * tmp;
            tmp_a.x = q.x * tmp;
            tmp_a.y = q.y * tmp;
            a[k*n + k1] = tmp_a;

            tmp = 1.0f / (tmp * z);

            cuComplex tmp_k_j;
            cuComplex tmp_i_j;

            for(i=k1; i<m; i++){
                //q = std::complex<T>(0.0F, 0.0F);
                q.x = 0.0f;
                q.y = 0.0f;

                for(j=k1; j<n; j++){
                    //q += conj(a(k,j)) * a(i,j);
                    //q.x += a[k*n + j].x * a[i*n + j].x;
                    //q.x += a[k*n + j].y * a[i*n + j].y;
                    //q.y += a[k*n + j].x * a[i*n + j].y;
                    //q.y -= a[k*n + j].y * a[i*n + j].x;
                    tmp_k_j = a[k*n + j];
                    tmp_i_j = a[i*n + j];
                    q.x += tmp_k_j.x * tmp_i_j.x;
                    q.x += tmp_k_j.y * tmp_i_j.y;
                    q.y += tmp_k_j.x * tmp_i_j.y;
                    q.y -= tmp_k_j.y * tmp_i_j.x;
                }

                //q /= z * (z + w);
                ////q.x = q.x / (z * (z + w));
                ////q.y = q.y / (z * (z + w));
                q.x *= tmp;
                q.y *= tmp;
                for(j=k1; j<n; j++){
                    //a(i,j) -= q * a(k,j);
                    //tmp_real  = q.x * a[k*n + j].x;
                    //tmp_real -= q.y * a[k*n + j].y;
                    //tmp_imag  = q.x * a[k*n + j].y;
                    //tmp_imag += q.y * a[k*n + j].x;
                    tmp_k_j = a[k*n + j];
                    tmp_real  = q.x * tmp_k_j.x;
                    tmp_real -= q.y * tmp_k_j.y;
                    tmp_imag  = q.x * tmp_k_j.y;
                    tmp_imag += q.y * tmp_k_j.x;
                    a[i*n + j].x -= tmp_real;
                    a[i*n + j].y -= tmp_imag;
                }
            }
            // PHASE TRANSFORMATION
            //q = -conj(a(k,k1)) / abs(a(k,k1));
            //w = sqrt(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            //w = sqrtf(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            //q.x = -a[k*n + k1].x / w;
            //q.y =  a[k*n + k1].y / w;
            tmp_a = a[k*n + k1];
            w = sqrtf(tmp_a.x * tmp_a.x + tmp_a.y * tmp_a.y);
            q.x = -tmp_a.x / w;
            q.y =  tmp_a.y / w;

            cuComplex tmp_i_k;

            for(i=k1; i<m; i++){
                //a(i,k1) *= q;
                //tmp_real  = a[i*n + k1].x * q.x;
                //tmp_real -= a[i*n + k1].y * q.y;
                //tmp_imag  = a[i*n + k1].x * q.y;
                //tmp_imag += a[i*n + k1].y * q.x;
                //a[i*n + k1].x = tmp_real;
                //a[i*n + k1].y = tmp_imag;
                tmp_i_k = a[i*n + k1];
                tmp_a.x  = tmp_i_k.x * q.x;
                tmp_a.x -= tmp_i_k.y * q.y;
                tmp_a.y  = tmp_i_k.x * q.y;
                tmp_a.y += tmp_i_k.y * q.x;
                a[i*n + k1] = tmp_a;
            }
        }
        k = k1;
    } /* End of while(1) */
    
#if 0
    //デバック
    for(i=0; i<8; i++){
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[i][0].real, a[i][0].imag,
                a[i][1].real, a[i][1].imag,
                a[i][2].real, a[i][2].imag,
                a[i][3].real, a[i][3].imag,
                a[i][4].real, a[i][4].imag,
                a[i][5].real, a[i][5].imag,
                a[i][6].real, a[i][6].imag,
                a[i][7].real, a[i][7].imag);
    }
#endif

    //} //for(k=0; k<pslength; k++)
}

__global__
//void gpu_Svd2(cuComplex *aa, float *ss, cuComplex *uu, cuComplex *vv,
//    int m, int n,
//    int *UsesFreq, int pslength,
//    float *bb, float *cc, float *tt,
//    const int st_freq
//    )
void gpu_Svd2(
    int m, int n,
    int *UsesFreq, int pslength,
    float *bb, float *cc, float *ss, float *tt,
    const int st_freq,
    float *eps_lst
    )
{
    float *b;
    float *c;
    float *t;

    int k;

    float eps, eta;
    int kk;
    float *s;

    kk = blockIdx.x + st_freq;
    k = threadIdx.x;

    if(kk >= pslength) return;

    if(k>=n)return;

    s = &ss[kk*n]; //m or n?
    b = &bb[kk*MAX_CH_NUM];
    c = &cc[kk*MAX_CH_NUM];
    t = &tt[kk*MAX_CH_NUM];

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

    eta = 1.5E-07F;

    //以下２つは最初の関数だけ行う
    // HOUSEHOLDER REDUCTION
    //c[0] = 0.0F;
    if(k==0) c[0] = 0.0F;

    // TOLERANCE FOR NEGLIGIBLE ELEMENTS
    //eps = 0.0F;
    //for(k=0; k<n; k++){
    s[k] = b[k];
    t[k] = c[k];

    //if(s[k] + t[k] > eps){
    eps = s[k] + t[k];
    //}
    //}

    float f_tmp;
    for (int i = n/2; i > 0; i >>= 1){ //2~1
        f_tmp = __shfl_xor(eps, i, n);
        eps = f_tmp > eps ? f_tmp : eps;
    }

    //eps *= eta;
    if(k==0){
        eps_lst[kk] = eps * eta;
    }
}

__global__
//void gpu_Svd3(cuComplex *aa, float *ss, cuComplex *uu, cuComplex *vv,
//    int m, int n,
//    int *UsesFreq, int pslength,
//    float *bb, float *cc, float *tt,
//    float *h_eps
//    )
void gpu_Svd3(cuComplex *uu, cuComplex *vv,
    int m, int n,
    int *UsesFreq, int pslength,
    const int st_freq
    )
{
    int nu; // considered number of cols of u
    int nv; // considered number of cols of v

    int i, j;

    int kk;

    cuComplex *u;
    cuComplex *v;

    kk = blockIdx.x + st_freq;
    int x = threadIdx.x; //n
    int y = threadIdx.y; //m

    //for(kk=0; kk<pslength; kk++){

        //if(!UsesFreq[kk]){
        //    continue;
        //}
        if(kk >= pslength) return;

        u = &uu[kk*m*n];
        v = &vv[kk*m*n];

        ////以下３つはconst
        //p = 0;
        nu = m;
        nv = n;

        //cuComplex comp0;
        //comp0.x = 0.0f;
        //comp0.y = 0.0f;

        // INITIALIZATION OF u AND v
        if(nu > 0){
            //for(i=0; i<m; i++){
            for(i=y; i<m; i+=blockDim.y){
                //for(j=0; j<nu; j++){
                for(j=x; j<nu; j+=blockDim.x){
                    if(i == j){
                        u[i*n + j].x = 1.0f;
                    }else{
                        u[i*n + j].x = 0.0f;
                    }
                    u[i*n + j].y = 0.0f;
                }
                //if(i == j){
                //    u[i*n + i].x = 1.0f; // swap loop i,j;
                //}
            }
        }

        if(nv > 0){
            //for(i=0; i<n; i++){
            for(i=y; i<n; i+=blockDim.y){
                //for(j=0; j<nv; j++){
                for(j=x; j<nv; j+=blockDim.x){
                    if(i == j){
                        v[i*n + j].x = 1.0f;
                    }else{
                    	v[i*n + j].x = 0.0f;
                    }
                    v[i*n + j].y = 0.0f;
                    //v[i*n + j] = comp0;
                }
                //if(i == j){
                //    v[i*n + i].x = 1.0f; // swap loop i,j;
                //}
            }
        }
    //}
}

#if 0
void cpu_Svd_QR(cuComplex *aa, float *ss, cuComplex *uu, cuComplex *vv,
     int m, int n,
     int *UsesFreq, int pslength,
     //float *bb, float *cc, float *tt,
     float *tt,
     float *h_eps
     )
{
    //int m;
    //int n;
    int p;  // transformation Conj(Tran(u)) is applied to the p vectors given in columns n, n+1, ..., n+p-1 of matrix a
    int nu; // considered number of cols of u
    int nv; // considered number of cols of v

    //float b[16];
    //float c[16];
    //float t[16];
    //float *b;
    //float *c;
    float *t;

    //COMPLEX_FLOAT q;
    cuComplex q;
    //COMPLEX_FLOAT r;
    cuComplex r;
    //int i, j, k, k1, L, L1, nM1, np;
    int i, j, k, L, L1, nM1, np;

    //float cs, eps, eta, f, g, h;
    float cs, eps, f, g, h;
    float sn;
    //float tol, w, x, y, z;
    //float w, x, y, z;
    float w, x, y;
    //float tmp, tmp2, tmp_real, tmp_imag;
    float tmp;
    //float f_real;
    //float f_imag;

    int kk;
    cuComplex *a;
    float *s;
    cuComplex *u;
    cuComplex *v;

    for(kk=0; kk<pslength; kk++){

    if(!UsesFreq[kk]){
        continue;
    }

    a = &aa[kk*m*n];
    s = &ss[kk*n]; //m or n?
    u = &uu[kk*m*n];
    v = &vv[kk*m*n];

    //b = &bb[kk*MAX_CH_NUM];
    //c = &cc[kk*MAX_CH_NUM];
    t = &tt[kk*MAX_CH_NUM];

    //----------------------------------------------------------------
    //m = amatrix_info.mic_num;
    //n = amatrix_info.mic_num;
    //m = localize_music_info.tf_channel_num;
    //n = localize_music_info.tf_channel_num;

    //以下３つはconst
    p = 0;
    nu = m;
    nv = n;

    //以下4つはconst
    //eta = 1.5E-07F;
    //tol = 1.5E-31F;
    np  = n + p;
    nM1 = n - 1;

    //Lは最初の関数は未使用
    L   = 0;  //loop変数

    //以下２つは最初の関数だけ行う
    // HOUSEHOLDER REDUCTION
    //c[0] = 0.0F;
    k = 0; // TOLERANCE FOR NEGLIGIBLE ELEMENTS後(while loop)は初期化される

    // TOLERANCE FOR NEGLIGIBLE ELEMENTS
    eps = h_eps[kk];

    // INITIALIZATION OF u AND v

    //QR DIAGONALIZATION

    int Test_flg;

    for(k=nM1; k>=0; k--){
        //デバック
        //LOGI("k = %d\n", k);

        //TEST FOR SPLIT
        while(1){
            Test_flg = 0;

            for(L=k; L>=0; L--){
                //デバック
                //LOGI("%d : %g, %g, eps = %g\n", L, t[L], s[L-1], eps);
                //if (ABS(t[L]) <= eps) goto Test;
                if(ABS(t[L]) <= eps){
                    //printf("test 1!!!!!\n");
                    Test_flg = 1;
                    break;
                }

                if(L > 0){
                    if(ABS(s[L - 1]) <= eps) break;
                }
            }

            //add
            if(!Test_flg){
                //CANCELLATION OF E(L)
                cs = 0.0F;
                sn = 1.0F;
                L1 = L - 1;

                for(i=L; i<=k; i++){
                    f = sn * t[i];
                    t[i] *= cs;

                    //デバック
                    //LOGI("%d : %g <= %g ?\n", i, f, eps);

                    //if(ABS(f) <= eps) goto Test;
                    if(ABS(f) <= eps){
                        //printf("test 2!!!!!\n");
                        Test_flg = 1;
                        break;
                    }

                    h = s[i];
                    //w = (float)sqrt(f * f + h * h);
                    w = sqrtf(f * f + h * h);
                    s[i] = w;
                    //cs = h / w;
                    //sn = -f / w;
                    tmp = 1.0f / w;
                    cs = h * tmp;
                    sn = -f * tmp;

                    if(nu>0){
                        for(j=0; j<n; j++){
                            //x = real(u(j,L1));
                            //y = real(u(j,i));
                            x = u[j*n + L1].x;
                            y = u[j*n + i].x;

                            //u(j,L1) = std::complex<T>(x * cs + y * sn, 0.0F);
                            tmp  = x * cs;
                            tmp += y * sn;
                            u[j*n + L1].x = tmp;
                            u[j*n + L1].y = 0.0f;

                            //u(j,i) = std::complex<T>(y * cs - x * sn, 0.0F);
                            tmp  = y * cs;
                            tmp -= x * sn;
                            u[j*n + i].x = tmp;
                            u[j*n + i].y = 0.0f;
                        }
                    }

                    if(np == n) continue;

                    for(j=n; j<np; j++){
                        //q = a(L1,j);
                        //q = a[L1][j];
                        q = a[L1*n + j];
                        //r = a(i,j);
                        r = a[i*n + j];

                        //a(L1,j) = q * cs + r * sn;
                        tmp  = q.x * cs;
                        tmp += r.x * sn;
                        a[L1*n + j].x = tmp;
                        tmp  = q.y * cs;
                        tmp += r.y * sn;
                        a[L1*n + j].y = tmp;

                        //a(i,j) = r * cs - q * sn;
                        tmp  = r.x * cs;
                        tmp -= q.x * sn;
                        a[i*n + j].x = tmp;
                        tmp  = r.y * cs;
                        tmp -= q.y * sn;
                        a[i*n + j].y = tmp;
                    }
                } //for(i=L; i<=k; i++){
            } //if(!Test_flg){

            //TEST FOR CONVERGENCE
//Test:     w = s[k];
            w = s[k];
            if(L==k) break;

            //ORIGIN SHIFT
            x = s[L];
            y = s[k - 1];
            g = t[k - 1];
            h = t[k];
            f = ((y - w) * (y + w) + (g - h) * (g + h)) / (2.0F * h * y);
            //g = (float)sqrt(f * f + 1.0F);
            g = sqrtf(f * f + 1.0F);
            if(f < 0.0F){ g = -g; }
            f = ((x - w) * (x + w) + (y / (f + g) - h) * h) / x;

            //QR STEP
            cs = 1.0F;
            sn = 1.0F;
            L1 = L + 1;
            for(i=L1; i<=k; i++){
                g = t[i];
                y = s[i];
                h = sn * g;
                g = cs * g;
                //w = (float)sqrt(h * h + f * f);
                w = sqrtf(h * h + f * f);
                t[i - 1] = w;
                //cs = f / w;
                //sn = h / w;
                tmp = 1.0f / w;
                cs = f * tmp;
                sn = h * tmp;
                f  = x * cs;
                f += g * sn;
                g  = g * cs;
                g -= x * sn;
                h  = y * sn;
                y  = y * cs;
                if(nv>0){
                    for(j=0; j<n; j++){
                        //x = real(v(j,i - 1));
                        //w = real(v(j,i));
                        //x = v[j][i-1].real;
                        x = v[j*n + (i-1)].x;
                        w = v[j*n + i].x;

                        //v(j,i - 1) = std::complex<T>(x * cs + w * sn, 0.0F);
                        tmp  = x * cs;
                        tmp += w * sn;
                        //v[j][i-1].real = tmp;
                        //v[j][i-1].imag = 0.0f;
                        v[j*n + (i-1)].x = tmp;
                        v[j*n + (i-1)].y = 0.0f;
                        //v(j,i) = std::complex<T>(w * cs - x * sn, 0.0F);
                        tmp  = w * cs;
                        tmp -= x * sn;
                        v[j*n + i].x = tmp;
                        v[j*n + i].y = 0.0f;
                    }
                }
                //w = (float)sqrt(h * h + f * f);
                w = sqrtf(h * h + f * f);
                s[i - 1] = w;
                //cs = f / w;
                //sn = h / w;
                tmp = 1.0f / w;
                cs = f * tmp;
                sn = h * tmp;
                f = cs * g + sn * y;
                x = cs * y - sn * g;
                if(nu > 0){
                    for(j=0; j<n; j++){
                        //y = real(u(j,i - 1));
                        //w = real(u(j,i));
                        //y = u[j][i-1].real;
                        y = u[j*n + (i-1)].x;
                        w = u[j*n + i].x;

                        //u(j,i - 1) = std::complex<T>(y * cs + w * sn, 0.0F);
                        tmp  = y * cs;
                        tmp += w * sn;
                        //u[j][i-1].real = tmp;
                        //u[j][i-1].imag = 0.0f;
                        u[j*n +(i-1)].x = tmp;
                        u[j*n +(i-1)].y = 0.0f;
                        //u(j,i) = std::complex<T>(w * cs - y * sn, 0.0F);
                        tmp  = w * cs;
                        tmp -= y * sn;
                        u[j*n + i].x = tmp;
                        u[j*n + i].y = 0.0f;
                    }
                }

                if(n==np) continue;

                for(j=n; j<np; j++){
                    //q = a(i - 1,j);
                    //r = a(i,j);
                    q = a[(i-1)*n + j];
                    r = a[i*n + j];

                    //a(i - 1,j) = q * cs + r * sn;
                    tmp  = q.x * cs;
                    tmp += r.x * sn;
                    a[(i-1)*n + j].x = tmp;
                    tmp  = q.y * cs;
                    tmp += r.y * sn;
                    a[(i-1)*n + j].y = tmp;
                    //a(i,j) = r * cs - q * sn;
                    tmp  = r.x * cs;
                    tmp -= q.x * sn;
                    a[i*n + j].x = tmp;
                    tmp  = r.y * cs;
                    tmp -= q.y * sn;
                    a[i*n + j].y = tmp;
                }
            }
            t[L] = 0.0F;
            t[k] = f;
            s[k] = x;
        } /* End of while(1) */

        //CONVERGENCE
        if(w>=0.0F) continue;

        s[k] = -w;

        if(nv==0) continue;

        for(j=0; j<n; j++){
            //v(j,k) = -v(j,k);
            v[j*n + k].x = -v[j*n + k].x;
            v[j*n + k].y = -v[j*n + k].y;
        }
    }
    } //for(kk=0; kk<pslength; kk++)
}
#endif

__global__
void gpu_Svd4(cuComplex *aa, float *ss, cuComplex *uu, cuComplex *vv,
    int m, int n,
    int *UsesFreq, int pslength,
    //float *bb, float *cc, float *tt,
    float *tt,
    float *h_eps,
    int st_freq
    )
{
    int p;  // transformation Conj(Tran(u)) is applied to the p vectors given in columns n, n+1, ..., n+p-1 of matrix a
    int nu; // considered number of cols of u
    int nv; // considered number of cols of v

    float *t;

    cuComplex q;
    cuComplex r;
    //int i, j, k, k1, L, L1, nM1, np;
    int i, j, k, L, L1, nM1, np;

    //float cs, eps, eta, f, g, h;
    float cs, eps, f, g, h;
    float sn;
    //float tol, w, x, y, z;
    //float w, x, y, z;
    float w, x, y;
    //float tmp, tmp2, tmp_real, tmp_imag;
    float tmp;
    //float f_real;
    //float f_imag;

    int kk;
    cuComplex *a;
    float *s;
    cuComplex *u;
    cuComplex *v;

    kk = blockIdx.x + st_freq;
    //int k = blockIdx.x + st_freq;

    if(kk >=pslength) return;

    a = &aa[kk*m*n];
    s = &ss[kk*n]; //m or n?
    u = &uu[kk*m*n];
    v = &vv[kk*m*n];

    //b = &bb[kk*MAX_CH_NUM];
    //c = &cc[kk*MAX_CH_NUM];
    t = &tt[kk*MAX_CH_NUM];

    //----------------------------------------------------------------
    //m = amatrix_info.mic_num;
    //n = amatrix_info.mic_num;
    //m = localize_music_info.tf_channel_num;
    //n = localize_music_info.tf_channel_num;

    //以下３つはconst
    p = 0;
    nu = m;
    nv = n;

    //以下4つはconst
    //eta = 1.5E-07F;
    //tol = 1.5E-31F;
    np  = n + p;
    nM1 = n - 1;

    //Lは最初の関数は未使用
    L   = 0;  //loop変数

    //以下２つは最初の関数だけ行う
    // HOUSEHOLDER REDUCTION
    //c[0] = 0.0F;
    k = 0; // TOLERANCE FOR NEGLIGIBLE ELEMENTS後(while loop)は初期化される

    // TOLERANCE FOR NEGLIGIBLE ELEMENTS
    eps = h_eps[kk];

    // INITIALIZATION OF u AND v

    //QR DIAGONALIZATION

    int Test_flg;

    for(k=nM1; k>=0; k--){
        //デバック
        //LOGI("k = %d\n", k);

        //TEST FOR SPLIT
        while(1){
            Test_flg = 0;

            for(L=k; L>=0; L--){
                //デバック
                //LOGI("%d : %g, %g, eps = %g\n", L, t[L], s[L-1], eps);
                //if(ABS(t[L]) <= eps) goto Test;
                if(ABS(t[L]) <= eps){
                    //printf("test 1!!!!!\n");
                    Test_flg = 1;
                    break;
                }

                if(L>0){
                    if(ABS(s[L - 1]) <= eps) break;
                }
            }

            //add sugisaki
            if(!Test_flg){
                //CANCELLATION OF E(L)
                cs = 0.0F;
                sn = 1.0F;
                L1 = L - 1;

                for(i=L; i<=k; i++){
                    f = sn * t[i];
                    t[i] *= cs;

                    //デバック
                    //LOGI("%d : %g <= %g ?\n", i, f, eps);

                    //if(ABS(f) <= eps) goto Test;
                    if(ABS(f) <= eps){
                        //printf("test 2!!!!!\n");
                        Test_flg = 1;
                        break;
                    }

                    h = s[i];
                    //w = (float)sqrt(f * f + h * h);
                    w = sqrtf(f * f + h * h);
                    s[i] = w;
                    //cs = h / w;
                    //sn = -f / w;
                    tmp = 1.0f / w;
                    cs = h * tmp;
                    sn = -f * tmp;

                    if(nu>0){
                        for(j=0; j<n; j++){
//if(blockIdx.x==0)printf("test1\n");
                            //x = real(u(j,L1));
                            //y = real(u(j,i));
                            x = u[j*n + L1].x;
                            y = u[j*n + i].x;

                            //u(j,L1) = std::complex<T>(x * cs + y * sn, 0.0F);
                            tmp  = x * cs;
                            tmp += y * sn;
                            u[j*n + L1].x = tmp;
                            u[j*n + L1].y = 0.0f;

                            //u(j,i) = std::complex<T>(y * cs - x * sn, 0.0F);
                            tmp  = y * cs;
                            tmp -= x * sn;
                            u[j*n + i].x = tmp;
                            u[j*n + i].y = 0.0f;
                        }
                    }

                    if(np == n) continue;

                    for(j=n; j<np; j++){
//if(blockIdx.x==0)printf("test2\n");
                        //q = a(L1,j);
                        //q = a[L1][j];
                        q = a[L1*n + j];
                        //r = a(i,j);
                        r = a[i*n + j];

                        cuComplex o_tmp;
                        //a(L1,j) = q * cs + r * sn;
#if 1
                        tmp  = q.x * cs;
                        tmp += r.x * sn;
                        a[L1*n + j].x = tmp;
                        tmp  = q.y * cs;
                        tmp += r.y * sn;
                        a[L1*n + j].y = tmp;
#else
                        o_tmp.x  = q.x * cs;
                        o_tmp.x += r.x * sn;
                        //a[L1*n + j].x = tmp;
                        o_tmp.y  = q.y * cs;
                        o_tmp.y += r.y * sn;
                        //a[L1*n + j].y = tmp;
                        a[L1*n + j] = o_tmp;
#endif

                        //a(i,j) = r * cs - q * sn;
#if 1
                        tmp  = r.x * cs;
                        tmp -= q.x * sn;
                        a[i*n + j].x = tmp;
                        tmp  = r.y * cs;
                        tmp -= q.y * sn;
                        a[i*n + j].y = tmp;
#else
                        o_tmp.x  = r.x * cs;
                        o_tmp.x -= q.x * sn;
                        //a[i*n + j].x = tmp;
                        o_tmp.y  = r.y * cs;
                        o_tmp.y -= q.y * sn;
                        //a[i*n + j].y = tmp;
                        a[i*n + j] = o_tmp;
#endif
                    }
                } //for(i=L; i<=k; i++)
            } //if(!Test_flg)

//TEST FOR CONVERGENCE
//Test:     w = s[k];
            w = s[k];
            if(L==k){ break; }

            //ORIGIN SHIFT
            x = s[L];
            y = s[k - 1];
            g = t[k - 1];
            h = t[k];
            f = ((y - w) * (y + w) + (g - h) * (g + h)) / (2.0F * h * y);
            //g = (float)sqrt(f * f + 1.0F);
            g = sqrtf(f * f + 1.0F);
            if(f < 0.0F){ g = -g; }
            f = ((x - w) * (x + w) + (y / (f + g) - h) * h) / x;

            //QR STEP
            cs = 1.0F;
            sn = 1.0F;
            L1 = L + 1;
            for(i=L1; i<=k; i++){
//if(blockIdx.x==0)printf("test3\n");
                g = t[i];
                y = s[i];
                h = sn * g;
                g = cs * g;
                //w = (float)sqrt(h * h + f * f);
                w = sqrtf(h * h + f * f);
                t[i - 1] = w;
                //cs = f / w;
                //sn = h / w;
                tmp = 1.0f / w;
                cs = f * tmp;
                sn = h * tmp;
                f  = x * cs;
                f += g * sn;
                g  = g * cs;
                g -= x * sn;
                h  = y * sn;
                y  = y * cs;

                if(nv>0){
                    for(j=0; j<n; j++){
//if(blockIdx.x==0)printf("test4\n");
#if 1
                        //x = real(v(j,i - 1));
                        //w = real(v(j,i));
                        //x = v[j][i-1].real;
                        x = v[j*n + (i-1)].x;
                        w = v[j*n + i].x;

                        //v(j,i - 1) = std::complex<T>(x * cs + w * sn, 0.0F);
                        tmp  = x * cs;
                        tmp += w * sn;
                        //v[j][i-1].real = tmp;
                        //v[j][i-1].imag = 0.0f;
                        v[j*n + (i-1)].x = tmp;
                        v[j*n + (i-1)].y = 0.0f;
                        //v(j,i) = std::complex<T>(w * cs - x * sn, 0.0F);
                        tmp  = w * cs;
                        tmp -= x * sn;
                        v[j*n + i].x = tmp;
                        v[j*n + i].y = 0.0f;
#else
                        x = v[j*n + (i-1)].x;
                        w = v[j*n + i].x;

                        cuComplex o_tmp;
                        o_tmp.x  = x * cs;
                        o_tmp.x += w * sn;
                        o_tmp.y = 0.0f;
                        v[j*n + (i-1)] = o_tmp;

                        o_tmp.x  = w * cs;
                        o_tmp.x -= x * sn;
                        o_tmp.y = 0.0f;
                        v[j*n + i] = o_tmp;
#endif
                    }
                }
                //w = (float)sqrt(h * h + f * f);
                w = sqrtf(h * h + f * f);
                s[i - 1] = w;
                //cs = f / w;
                //sn = h / w;
                tmp = 1.0f / w;
                cs = f * tmp;
                sn = h * tmp;
                f = cs * g + sn * y;
                x = cs * y - sn * g;
                if(nu>0){
                    for(j=0; j<n; j++){
//if(blockIdx.x==0)printf("test5\n");
                        //y = real(u(j,i - 1));
                        //w = real(u(j,i));
                        //y = u[j][i-1].real;
                        y = u[j*n + (i-1)].x;
                        w = u[j*n + i].x;

                        //u(j,i - 1) = std::complex<T>(y * cs + w * sn, 0.0F);
                        tmp  = y * cs;
                        tmp += w * sn;
                        //u[j][i-1].real = tmp;
                        //u[j][i-1].imag = 0.0f;
                        u[j*n +(i-1)].x = tmp;
                        u[j*n +(i-1)].y = 0.0f;
                        //u(j,i) = std::complex<T>(w * cs - y * sn, 0.0F);
                        tmp  = w * cs;
                        tmp -= y * sn;
                        u[j*n + i].x = tmp;
                        u[j*n + i].y = 0.0f;
                    }
                }

                if(n==np){ continue; }

                for(j=n; j<np; j++){
//if(blockIdx.x==0)printf("test6\n");
                    //q = a(i - 1,j);
                    //r = a(i,j);
                    q = a[(i-1)*n + j];
                    r = a[i*n + j];

                    //a(i - 1,j) = q * cs + r * sn;
                    tmp  = q.x * cs;
                    tmp += r.x * sn;
                    a[(i-1)*n + j].x = tmp;
                    tmp  = q.y * cs;
                    tmp += r.y * sn;
                    a[(i-1)*n + j].y = tmp;
                    //a(i,j) = r * cs - q * sn;
                    tmp  = r.x * cs;
                    tmp -= q.x * sn;
                    a[i*n + j].x = tmp;
                    tmp  = r.y * cs;
                    tmp -= q.y * sn;
                    a[i*n + j].y = tmp;
                }
            }
            t[L] = 0.0F;
            t[k] = f;
            s[k] = x;
        } /* End of while(1) */


        //CONVERGENCE
        if(w>=0.0F){ continue; }

        s[k] = -w;

        if(nv==0){ continue; }

        for(j=0; j<n; j++){
//if(blockIdx.x==0)printf("test7\n");
            //v(j,k) = -v(j,k);
            v[j*n + k].x = -v[j*n + k].x;
            v[j*n + k].y = -v[j*n + k].y;
        }
    }
    //} //for(kk=0; kk<pslength; kk++)
}



__global__
//void gpu_Svd5(cuComplex *aa, float *ss, cuComplex *uu, cuComplex *vv,
//    int m, int n,
//    int *UsesFreq, int pslength,
//    float *bb, float *cc, float *tt,
//    //float *h_eps
//    int st_freq
//    )
void gpu_Svd5(cuComplex *aa, float *ss, cuComplex *uu, cuComplex *vv,
    int m, int n,
    int *UsesFreq, int pslength,
    int st_freq
    )
{
    //int m;
    //int n;
    int p;  // transformation Conj(Tran(u)) is applied to the p vectors given in columns n, n+1, ..., n+p-1 of matrix a
    int nu; // considered number of cols of u
    int nv; // considered number of cols of v

    //float b[16];
    //float c[16];
    //float t[16];
    //float *b;
    //float *c;
    //float *t;

    //COMPLEX_FLOAT q;
    cuComplex q;
    //COMPLEX_FLOAT r;
    //cuComplex r;
    //int i, j, k, k1, L, L1, nM1, np;
    int i, j, k, np;

    //float cs, eps, eta, f, g, h;
    float g;
    //float sn;
    //float tol, w, x, y, z;
    //float tmp, tmp2, tmp_real, tmp_imag;
    //float f_real;
    //float f_imag;

    int kk;
    cuComplex *a;
    float *s;
    cuComplex *u;
    cuComplex *v;

    kk = blockIdx.x + st_freq;

    if(kk>=pslength) return;

    a = &aa[kk*m*n];
    s = &ss[kk*n]; //m or n?
    u = &uu[kk*m*n];
    v = &vv[kk*m*n];

    //b = &bb[kk*MAX_CH_NUM];
    //c = &cc[kk*MAX_CH_NUM];
    //t = &tt[kk*MAX_CH_NUM];

//----------------------------------------------------------------
    //以下３つはconst
    p = 0;
    nu = m;
    nv = n;

    //以下4つはconst
    //eta = 1.5E-07F;
    //tol = 1.5E-31F;
    np  = n + p;
    //nM1 = n - 1;

    //Lは最初の関数は未使用
    //L   = 0;  //loop変数

    //以下２つは最初の関数だけ行う
    // HOUSEHOLDER REDUCTION
    //c[0] = 0.0F;
    ////k = 0; // TOLERANCE FOR NEGLIGIBLE ELEMENTS後(while loop)は初期化される

    //デバック
    //LOGI("(%f, %f), (%f, %f)\n", a[0][0].real, a[0][0].imag, a[0][1].real, a[0][1].imag);


    // TOLERANCE FOR NEGLIGIBLE ELEMENTS

    //eps = h_eps[kk];

    // INITIALIZATION OF u AND v


    //QR DIAGONALIZATION


    //SORT SINGULAR VALUES
    for(k=0; k<n; k++){ /* sort descending */
        g = -1.0F;
        j = k;
        for(i=k; i<n; i++){ /* sort descending */
            if(s[i]<=g){ continue; }

            g = s[i];
            j = i;
        }

        if(j==k){ continue; }

        s[j] = s[k];
        s[k] = g;
        if(nv>0){
            for(i=0; i<n; i++){
                //q = v(i,j);
                //v(i,j) = v(i,k);
                //v(i,k) = q;

                //sugisaki
                //q = v[i][j];
                //v[i][j] = v[i][k];
                //v[i][k] = q;
                q.x = v[i*n + j].x;
                q.y = v[i*n + j].y;
                //v[i][j] = v[i][k];
                v[i*n + j] = v[i*n + k];
                v[i*n + k].x = q.x;
                v[i*n + k].y = q.y;
            }
        }

        if(nu>0){
            for(i=0; i<n; i++){
                //q = u(i,j);
                //u(i,j) = u(i,k);
                //u(i,k) = q;

                //sugisaki
                //q = u[i][j];
                //u[i][j] = u[i][k];
                //u[i][k] = q;
                q.x = u[i*n + j].x;
                q.y = u[i*n + j].y;
                //u[i][j] = u[i][k];
                u[i*n + j] = u[i*n + k];
                u[i*n + k].x = q.x;
                u[i*n + k].y = q.y;
            }
        }

        if(n==np){ continue; }

        for(i=n; i<np; i++){
            //q = a(j,i);
            //a(j,i) = a(k,i);
            //a(k,i) = q;
            q = a[j*n + i];
            a[j*n + i] = a[k*n + i];
            a[k*n + i] = q;
        }
    }

}


__global__
//void gpu_Svd6(cuComplex *aa, float *ss, cuComplex *uu, cuComplex *vv,
//    int m, int n,
//    int *UsesFreq, int pslength,
//    float *bb, float *cc, float *tt,
//    int st_freq
//    )
//void gpu_Svd6(cuComplex *aa, cuComplex *uu, cuComplex *vv,
//    int m, int n,
//    int *UsesFreq, int pslength,
//    float *bb, float *cc,
//    int st_freq
//    )
void gpu_Svd6(cuComplex *aa, cuComplex *uu, cuComplex *vv,
    int m, int n,
    int *UsesFreq, int pslength,
    float *bb, float *cc,
    int st_freq
    )
{
    //int m;
    //int n;
    //int p;  // transformation Conj(Tran(u)) is applied to the p vectors given in columns n, n+1, ..., n+p-1 of matrix a
    int nu; // considered number of cols of u
    int nv; // considered number of cols of v

    float *b;
    float *c;
    //float *t;

    //COMPLEX_FLOAT q;
    cuComplex q;
    //COMPLEX_FLOAT r;
    //cuComplex r;
    //int i, j, k, k1, L, L1, nM1, np;
    int i, j, k, k1, nM1;

    //float cs, eps, eta, f, g, h;
    //float sn;
    //float tol, w, x, y, z;
    float w;
    float tmp, tmp2, tmp_real, tmp_imag;
    //float f_real;
    //float f_imag;

    int kk;
    cuComplex *a;
    //float *s;
    cuComplex *u;
    cuComplex *v;

    kk = blockIdx.x + st_freq;
//    for(kk=0; kk<pslength; kk++){
//
//        if(!UsesFreq[kk]){
//            continue;
//        }

        a = &aa[kk*m*n];
        //s = &ss[kk*n]; //m or n?
        u = &uu[kk*m*n];
        v = &vv[kk*m*n];

        b = &bb[kk*MAX_CH_NUM];
        c = &cc[kk*MAX_CH_NUM];
        //t = &tt[kk*MAX_CH_NUM];

//----------------------------------------------------------------
    //m = amatrix_info.mic_num;
    //n = amatrix_info.mic_num;
    //m = localize_music_info.tf_channel_num;
    //n = localize_music_info.tf_channel_num;

    //以下３つはconst
    //p = 0;
    nu = m;
    nv = n;

    //以下4つはconst
    //eta = 1.5E-07F;
    //tol = 1.5E-31F;
    //np  = n + p;
    nM1 = n - 1;

    //Lは最初の関数は未使用
    //L   = 0;  //loop変数

    //以下２つは最初の関数だけ行う
    // HOUSEHOLDER REDUCTION
    //c[0] = 0.0F;
    //k = 0; // TOLERANCE FOR NEGLIGIBLE ELEMENTS後(while loop)は初期化される


    // TOLERANCE FOR NEGLIGIBLE ELEMENTS
    //eps = h_eps[kk];


    // INITIALIZATION OF u AND v


    //QR DIAGONALIZATION


    //SORT SINGULAR VALUES


    //BACK TRANSFORMATION
    if(nu>0){
        for(k=nM1; k>=0; k--){
            if (b[k] == 0.0F) continue;

            cuComplex a_tmp = a[k*n + k];
            //w = sqrt(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);
            //w = sqrtf(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);
            w = sqrtf(a_tmp.x * a_tmp.x + a_tmp.y * a_tmp.y);
            //q = -a(k,k) / abs(a(k,k));
            //q.x = -a[k*n + k].x / w;
            //q.y = -a[k*n + k].y / w;
            tmp2 = 1.0f / (w * b[k]);
            tmp = 1.0f / w;
            q.x = -a_tmp.x * tmp;
            q.y = -a_tmp.y * tmp;

            for(j=0; j<nu; j++){
                //u(k,j) *= q;
                cuComplex u_tmp = u[k*n + j];
                cuComplex o_tmp;
#if 0
                tmp_real  = u_tmp.x * q.x;
                tmp_real -= u_tmp.y * q.y;
                tmp_imag  = u_tmp.x * q.y;
                tmp_imag += u_tmp.y * q.x;
                u[k*n + j].x = tmp_real;
                u[k*n + j].y = tmp_imag;
#else
                o_tmp.x  = u_tmp.x * q.x;
                o_tmp.x -= u_tmp.y * q.y;
                o_tmp.y  = u_tmp.x * q.y;
                o_tmp.y += u_tmp.y * q.x;
                u[k*n + j] = o_tmp;
#endif
            }

            for(j=0; j<nu; j++){
                //q = std::complex<T>(0.0F, 0.0F);
                q.x = 0.0f;
                q.y = 0.0f;
                for(i=k; i<m; i++){
                    //q += conj(a(i,k)) * u(i,j);
                    cuComplex a_tmp2 = a[i*n + k];
                    cuComplex u_tmp2 = u[i*n + j];
                    q.x += a_tmp2.x * u_tmp2.x;
                    q.x += a_tmp2.y * u_tmp2.y;
                    q.y += a_tmp2.x * u_tmp2.y;
                    q.y -= a_tmp2.y * u_tmp2.x;
                }

                //w = sqrt(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);
                //w = sqrtf(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y); // このループ内でaは更新しないので不要
                //q /= abs(a(k,k)) * b[k];
                //q.x = q.x / (w * b[k]);
                //q.y = q.y / (w * b[k]);
                q.x = q.x * tmp2;
                q.y = q.y * tmp2;

                for(i=k; i<m; i++){
                    //u(i,j) -= q * a(i,k);
                    cuComplex a_tmp2 = a[i*n + k];
                    tmp  = q.x * a_tmp2.x;
                    tmp -= q.y * a_tmp2.y;
                    u[i*n + j].x -= tmp;
                    tmp  = q.x * a_tmp2.y;
                    tmp += q.y * a_tmp2.x;
                    u[i*n + j].y -= tmp;
                }
            }
        }
    }

    if(nv>0 && n>1){
        for(k=n-2; k>=0; k--){
            k1 = k + 1;
            if(c[k1] == 0.0F){ continue; }

            cuComplex a_tmp = a[k*n + k1];
            //w = sqrt(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            //w = sqrtf(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            w = sqrtf(a_tmp.x * a_tmp.x + a_tmp.y * a_tmp.y);
            //q = -conj(a(k,k1)) / abs(a(k,k1));
            //q.x = -a[k*n + k1].x / w;
            //q.y =  a[k*n + k1].y / w;
            tmp2 = 1.0f / (w * c[k1]);
            tmp = 1.0f / w;
            q.x = -a_tmp.x * tmp;
            q.y =  a_tmp.y * tmp;

            for(j=0; j<nv; j++){
                //v(k1,j) *= q;
                //tmp_real  = v[k1][j].real * q.x;
                //tmp_real -= v[k1][j].imag * q.y;
                //tmp_imag  = v[k1][j].real * q.y;
                //tmp_imag += v[k1][j].imag * q.x;
                //v[k1][j].real = tmp_real;
                //v[k1][j].imag = tmp_imag;
                cuComplex v_tmp = v[k1*n + j];
                cuComplex o_tmp;
#if 0
                tmp_real  = v_tmp.x * q.x;
                tmp_real -= v_tmp.y * q.y;
                tmp_imag  = v_tmp.x * q.y;
                tmp_imag += v_tmp.y * q.x;
                v[k1*n + j].x = tmp_real;
                v[k1*n + j].y = tmp_imag;
#else
                o_tmp.x  = v_tmp.x * q.x;
                o_tmp.x -= v_tmp.y * q.y;
                o_tmp.y  = v_tmp.x * q.y;
                o_tmp.y += v_tmp.y * q.x;
                v[k1*n + j] = o_tmp;
#endif
            }

            for(j=0; j<nv; j++){
                //q = std::complex<T>(0.0F, 0.0F);
                q.x = 0.0f;
                q.y = 0.0f;

                for(i=k1; i<n; i++){
                    //q += a(k,i) * v(i,j);
                    cuComplex a_tmp2 = a[k*n + i];
                    cuComplex v_tmp2 = v[i*n + j];
                    q.x += a_tmp2.x * v_tmp2.x;
                    q.x -= a_tmp2.y * v_tmp2.y;
                    q.y += a_tmp2.x * v_tmp2.y;
                    q.y += a_tmp2.y * v_tmp2.x;
                }

                //w = sqrt(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
                //w = sqrtf(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y); // このループ内でaは更新しないので不要
                //q = q / (abs(a(k,k1)) * c[k1]);
                //q.x = q.x / (w * c[k1]);
                //q.y = q.y / (w * c[k1]);
                q.x = q.x * tmp2;
                q.y = q.y * tmp2;

                for(i=k1; i<n; i++){
                    //v(i,j) -= q * conj(a(k,i));
                    cuComplex a_tmp2 = a[k*n + i];
                    tmp  =  q.x * a_tmp2.x;
                    tmp +=  q.y * a_tmp2.y;
                    v[i*n + j].x -= tmp;
                    tmp  = -q.x * a_tmp2.y;
                    tmp +=  q.y * a_tmp2.x;
                    v[i*n + j].y -= tmp;
                }
            }
        }
    } //if(nv > 0 && n > 1)
    //} //for(k=0; k<pslength; k++)
}


#if 0
void cpu_Svd2(cuComplex *aa, float *ss, cuComplex *uu, cuComplex *vv,
    int m, int n,
    int *UsesFreq, int pslength,
    float *bb, float *cc, float *tt,
    float *h_eps
    )
{
    //int m;
    //int n;
    int p;  // transformation Conj(Tran(u)) is applied to the p vectors given in columns n, n+1, ..., n+p-1 of matrix a
    int nu; // considered number of cols of u
    int nv; // considered number of cols of v

    //float b[16];
    //float c[16];
    //float t[16];
    float *b;
    float *c;
    float *t;

    //COMPLEX_FLOAT q;
    cuComplex q;
    //COMPLEX_FLOAT r;
    cuComplex r;
    int i, j, k, k1, L, L1, nM1, np;

    float cs, eps, eta, f, g, h;
    float sn;
    float tol, w, x, y, z;
    float tmp, tmp2, tmp_real, tmp_imag;
    //float f_real;
    //float f_imag;

    int kk;
    cuComplex *a;
    float *s;
    cuComplex *u;
    cuComplex *v;

    for(kk=0; kk<pslength; kk++){
        if(!UsesFreq[kk]){
            continue;
        }

        a = &aa[kk*m*n];
        s = &ss[kk*n]; //m or n?
        u = &uu[kk*m*n];
        v = &vv[kk*m*n];

        b = &bb[kk*MAX_CH_NUM];
        c = &cc[kk*MAX_CH_NUM];
        t = &tt[kk*MAX_CH_NUM];

//----------------------------------------------------------------
    //m = amatrix_info.mic_num;
    //n = amatrix_info.mic_num;
    //m = localize_music_info.tf_channel_num;
    //n = localize_music_info.tf_channel_num;

    //以下３つはconst
    p = 0;
    nu = m;
    nv = n;

    //以下4つはconst
    eta = 1.5E-07F;
    tol = 1.5E-31F;
    np  = n + p;
    nM1 = n - 1;

    //Lは最初の関数は未使用
    L   = 0;  //loop変数

    //以下２つは最初の関数だけ行う
    // HOUSEHOLDER REDUCTION
    c[0] = 0.0F;
    k = 0; // TOLERANCE FOR NEGLIGIBLE ELEMENTS後(while loop)は初期化される

    //デバック
    //LOGI("(%f, %f), (%f, %f)\n", a[0][0].real, a[0][0].imag, a[0][1].real, a[0][1].imag);

#if 0
    //デバック
    for(i=0; i<8; i++){
        LOGI("(%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g), (%g,%g)\n",
                a[i][0].real, a[i][0].imag,
                a[i][1].real, a[i][1].imag,
                a[i][2].real, a[i][2].imag,
                a[i][3].real, a[i][3].imag,
                a[i][4].real, a[i][4].imag,
                a[i][5].real, a[i][5].imag,
                a[i][6].real, a[i][6].imag,
                a[i][7].real, a[i][7].imag);
    }
#endif

    // TOLERANCE FOR NEGLIGIBLE ELEMENTS
#if 0
    eps = 0.0F;
    for(k=0; k<n; k++){
        s[k] = b[k];
        t[k] = c[k];
        if(s[k] + t[k] > eps){
            eps = s[k] + t[k];
        }
    }
    eps *= eta;
    //デバック
    //LOGI("eps = %g\n", eps);
#endif
    eps = h_eps[kk];

    // INITIALIZATION OF u AND v
#if 0
    if(nu>0){
        //for(j=0; j<nu; j++){
            //for(i=0; i<m; i++){
        for(i=0; i<m; i++){
            for(j=0; j<nu; j++){
                //u(i,j) = std::complex<T>(0.0F, 0.0F);
                //u[i][j].real = 0.0f;
                //u[i][j].imag = 0.0f;
                u[i*n + j].x = 0.0f;
                u[i*n + j].y = 0.0f;
            }
            //u(j,j) = std::complex<T>(1.0F, 0.0F);
            //u[j][j].real = 1.0f; // skip because already set! u[j][j].imag = 0.0f;
            u[i*n + i].x = 1.0f; // swap loop i,j;
        }
    }

    if(nv>0){
        //for(j=0; j<nv; j++){
            //for(i=0; i<n; i++){
        for(i=0; i<n; i++){
            for(j=0; j<nv; j++){
                //v(i,j) = std::complex<T>(0.0F, 0.0F);
                v[i*n + j].x = 0.0f;
                v[i*n + j].y = 0.0f;
            }
            //v(j,j) = std::complex<T>(1.0F, 0.0F);
            //v[j][j].real = 1.0f; // skip because already set! v[j][j].imag = 0.0f;
            v[i*n + i].x = 1.0f; // swap loop i,j;
        }
    }
#endif



    //QR DIAGONALIZATION
#if 0
    for(k=nM1; k>=0; k--){
        //デバック
        //LOGI("k = %d\n", k);

        //TEST FOR SPLIT
        while(1){
            for(L=k; L>=0; L--){
                //デバック
                //LOGI("%d : %g, %g, eps = %g\n", L, t[L], s[L-1], eps);
                if (ABS(t[L]) <= eps) goto Test;
                if(L > 0){
                    if (ABS(s[L - 1]) <= eps) break;
                }
            }

            //CANCELLATION OF E(L)
            cs = 0.0F;
            sn = 1.0F;
            L1 = L - 1;
            for(i=L; i<=k; i++){
                f = sn * t[i];
                t[i] *= cs;

                //デバック
                //LOGI("%d : %g <= %g ?\n", i, f, eps);

                if(ABS(f)<=eps) goto Test;

                h = s[i];
                //w = (float)sqrt(f * f + h * h);
                w = sqrtf(f * f + h * h);
                s[i] = w;
                //cs = h / w;
                //sn = -f / w;
                tmp = 1.0f / w;
                cs = h * tmp;
                sn = -f * tmp;

                if(nu>0){
                    for(j=0; j<n; j++){
                        //x = real(u(j,L1));
                        //y = real(u(j,i));
                        x = u[j*n + L1].x;
                        y = u[j*n + i].x;

                        //u(j,L1) = std::complex<T>(x * cs + y * sn, 0.0F);
                        tmp  = x * cs;
                        tmp += y * sn;
                        u[j*n + L1].x = tmp;
                        u[j*n + L1].y = 0.0f;

                        //u(j,i) = std::complex<T>(y * cs - x * sn, 0.0F);
                        tmp  = y * cs;
                        tmp -= x * sn;
                        u[j*n + i].x = tmp;
                        u[j*n + i].y = 0.0f;
                    }
                }

                if(np==n){ continue; }

                for(j=n; j<np; j++){
                    //q = a(L1,j);
                    //q = a[L1][j];
                    q = a[L1*n + j];
                    //r = a(i,j);
                    r = a[i*n + j];

                    //a(L1,j) = q * cs + r * sn;
                    tmp  = q.x * cs;
                    tmp += r.x * sn;
                    a[L1*n + j].x = tmp;
                    tmp  = q.y * cs;
                    tmp += r.y * sn;
                    a[L1*n + j].y = tmp;

                    //a(i,j) = r * cs - q * sn;
                    tmp  = r.x * cs;
                    tmp -= q.x * sn;
                    a[i*n + j].x = tmp;
                    tmp  = r.y * cs;
                    tmp -= q.y * sn;
                    a[i*n + j].y = tmp;
                }
            }

            //TEST FOR CONVERGENCE
Test:       w = s[k];
            if(L==k){ break; }

            //ORIGIN SHIFT
            x = s[L];
            y = s[k - 1];
            g = t[k - 1];
            h = t[k];
            f = ((y - w) * (y + w) + (g - h) * (g + h)) / (2.0F * h * y);
            //g = (float)sqrt(f * f + 1.0F);
            g = sqrtf(f * f + 1.0F);
            if(f < 0.0F){ g = -g; }
            f = ((x - w) * (x + w) + (y / (f + g) - h) * h) / x;

            //QR STEP
            cs = 1.0F;
            sn = 1.0F;
            L1 = L + 1;
            for(i=L1; i<=k; i++){
                g = t[i];
                y = s[i];
                h = sn * g;
                g = cs * g;
                //w = (float)sqrt(h * h + f * f);
                w = sqrtf(h * h + f * f);
                t[i - 1] = w;
                //cs = f / w;
                //sn = h / w;
                tmp = 1.0f / w;
                cs = f * tmp;
                sn = h * tmp;
                f  = x * cs;
                f += g * sn;
                g  = g * cs;
                g -= x * sn;
                h  = y * sn;
                y  = y * cs;
                if(nv>0){
                    for(j=0; j<n; j++){
                        //x = real(v(j,i - 1));
                        //w = real(v(j,i));
                        //x = v[j][i-1].real;
                        x = v[j*n + (i-1)].x;
                        w = v[j*n + i].x;

                        //v(j,i - 1) = std::complex<T>(x * cs + w * sn, 0.0F);
                        tmp  = x * cs;
                        tmp += w * sn;
                        //v[j][i-1].real = tmp;
                        //v[j][i-1].imag = 0.0f;
                        v[j*n + (i-1)].x = tmp;
                        v[j*n + (i-1)].y = 0.0f;
                        //v(j,i) = std::complex<T>(w * cs - x * sn, 0.0F);
                        tmp  = w * cs;
                        tmp -= x * sn;
                        v[j*n + i].x = tmp;
                        v[j*n + i].y = 0.0f;
                    }
                }
                //w = (float)sqrt(h * h + f * f);
                w = sqrtf(h * h + f * f);
                s[i - 1] = w;
                //cs = f / w;
                //sn = h / w;
                tmp = 1.0f / w;
                cs = f * tmp;
                sn = h * tmp;
                f = cs * g + sn * y;
                x = cs * y - sn * g;
                if(nu>0){
                    for(j=0; j<n; j++){
                        //y = real(u(j,i - 1));
                        //w = real(u(j,i));
                        //y = u[j][i-1].real;
                        y = u[j*n + (i-1)].x;
                        w = u[j*n + i].x;

                        //u(j,i - 1) = std::complex<T>(y * cs + w * sn, 0.0F);
                        tmp  = y * cs;
                        tmp += w * sn;
                        //u[j][i-1].real = tmp;
                        //u[j][i-1].imag = 0.0f;
                        u[j*n +(i-1)].x = tmp;
                        u[j*n +(i-1)].y = 0.0f;
                        //u(j,i) = std::complex<T>(w * cs - y * sn, 0.0F);
                        tmp  = w * cs;
                        tmp -= y * sn;
                        u[j*n + i].x = tmp;
                        u[j*n + i].y = 0.0f;
                    }
                }

                if(n==np){ continue; }

                for(j=n; j<np; j++){
                    //q = a(i - 1,j);
                    //r = a(i,j);
                    q = a[(i-1)*n + j];
                    r = a[i*n + j];
                    
                    //a(i - 1,j) = q * cs + r * sn;
                    tmp  = q.x * cs;
                    tmp += r.x * sn;
                    a[(i-1)*n + j].x = tmp;
                    tmp  = q.y * cs;
                    tmp += r.y * sn;
                    a[(i-1)*n + j].y = tmp;
                    //a(i,j) = r * cs - q * sn;
                    tmp  = r.x * cs;
                    tmp -= q.x * sn;
                    a[i*n + j].x = tmp;
                    tmp  = r.y * cs;
                    tmp -= q.y * sn;
                    a[i*n + j].y = tmp;
                }
            }
            t[L] = 0.0F;
            t[k] = f;
            s[k] = x;
        } /* End of while(1) */

        //CONVERGENCE
        if (w >= 0.0F) continue;

        s[k] = -w;

        if(nv==0){ continue; }

        for(j=0; j<n; j++){
            //v(j,k) = -v(j,k);
            v[j*n + k].x = -v[j*n + k].x;
            v[j*n + k].y = -v[j*n + k].y;
        }
    }
#endif
    
#if 0
    //SORT SINGULAR VALUES
    for(k=0; k<n; k++){ /* sort descending */
        g = -1.0F;
        j = k;
        for(i=k; i<n; i++){ /* sort descending */
            if(s[i]<=g){ continue; }

            g = s[i];
            j = i;
        }

        if(j==k){ continue; }

        s[j] = s[k];
        s[k] = g;
        if(nv>0){
            for(i=0; i<n; i++){
                //q = v(i,j);
                //v(i,j) = v(i,k);
                //v(i,k) = q;

                //sugisaki
                //q = v[i][j];
                //v[i][j] = v[i][k];
                //v[i][k] = q;
                q.x = v[i*n + j].x;
                q.y = v[i*n + j].y;
                //v[i][j] = v[i][k];
                v[i*n + j] = v[i*n + k];
                v[i*n + k].x = q.x;
                v[i*n + k].y = q.y;
            }
        }

        if(nu>0){
            for(i=0; i<n; i++){
                //q = u(i,j);
                //u(i,j) = u(i,k);
                //u(i,k) = q;

                //sugisaki
                //q = u[i][j];
                //u[i][j] = u[i][k];
                //u[i][k] = q;
                q.x = u[i*n + j].x;
                q.y = u[i*n + j].y;
                //u[i][j] = u[i][k];
                u[i*n + j] = u[i*n + k];
                u[i*n + k].x = q.x;
                u[i*n + k].y = q.y;
            }
        }

        if(n==np){ continue; }

        for(i=n; i<np; i++){
            //q = a(j,i);
            //a(j,i) = a(k,i);
            //a(k,i) = q;
            q = a[j*n + i];
            a[j*n + i] = a[k*n + i];
            a[k*n + i] = q;
        }
    }
#endif

    //BACK TRANSFORMATION
    if(nu>0){
        for(k=nM1; k>=0; k--){
            if(b[k]==0.0F){ continue; }

            //w = sqrt(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);
            w = sqrtf(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);
            //q = -a(k,k) / abs(a(k,k));
            //q.x = -a[k*n + k].x / w;
            //q.y = -a[k*n + k].y / w;
            tmp2 = 1.0f / (w * b[k]);
            tmp = 1.0f / w;
            q.x = -a[k*n + k].x * tmp;
            q.y = -a[k*n + k].y * tmp;

            for(j=0; j<nu; j++){
                //u(k,j) *= q;
                tmp_real  = u[k*n + j].x * q.x;
                tmp_real -= u[k*n + j].y * q.y;
                tmp_imag  = u[k*n + j].x * q.y;
                tmp_imag += u[k*n + j].y * q.x;
                u[k*n + j].x = tmp_real;
                u[k*n + j].y = tmp_imag;
            }

            for(j=0; j<nu; j++){
                //q = std::complex<T>(0.0F, 0.0F);
                q.x = 0.0f;
                q.y = 0.0f;
                for(i=k; i<m; i++){
                    //q += conj(a(i,k)) * u(i,j);
                    q.x += a[i*n + k].x * u[i*n + j].x;
                    q.x += a[i*n + k].y * u[i*n + j].y;
                    q.y += a[i*n + k].x * u[i*n + j].y;
                    q.y -= a[i*n + k].y * u[i*n + j].x;
                }

                //w = sqrt(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y);
                //w = sqrtf(a[k*n + k].x * a[k*n + k].x + a[k*n + k].y * a[k*n + k].y); // このループ内でaは更新しないので不要
                //q /= abs(a(k,k)) * b[k];
                //q.x = q.x / (w * b[k]);
                //q.y = q.y / (w * b[k]);
                q.x = q.x * tmp2;
                q.y = q.y * tmp2;

                for(i=k; i<m; i++){
                    //u(i,j) -= q * a(i,k);
                    tmp  = q.x * a[i*n + k].x;
                    tmp -= q.y * a[i*n + k].y;
                    u[i*n + j].x -= tmp;
                    tmp  = q.x * a[i*n + k].y;
                    tmp += q.y * a[i*n + k].x;
                    u[i*n + j].y -= tmp;
                }
            }
        }
    }

    if(nv>0 && n>1){
        for(k=n-2; k>=0; k--){
            k1 = k + 1;
            if(c[k1]==0.0F){ continue; }

            //w = sqrt(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            w = sqrtf(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
            //q = -conj(a(k,k1)) / abs(a(k,k1));
            //q.x = -a[k*n + k1].x / w;
            //q.y =  a[k*n + k1].y / w;
            tmp2 = 1.0f / (w * c[k1]);
            tmp = 1.0f / w;
            q.x = -a[k*n + k1].x * tmp;
            q.y =  a[k*n + k1].y * tmp;

            for(j=0; j<nv; j++){
                //v(k1,j) *= q;
                //tmp_real  = v[k1][j].real * q.x;
                //tmp_real -= v[k1][j].imag * q.y;
                //tmp_imag  = v[k1][j].real * q.y;
                //tmp_imag += v[k1][j].imag * q.x;
                tmp_real  = v[k1*n + j].x * q.x;
                tmp_real -= v[k1*n + j].y * q.y;
                tmp_imag  = v[k1*n + j].x * q.y;
                tmp_imag += v[k1*n + j].y * q.x;
                //v[k1][j].real = tmp_real;
                //v[k1][j].imag = tmp_imag;
                v[k1*n + j].x = tmp_real;
                v[k1*n + j].y = tmp_imag;
            }

            for(j=0; j<nv; j++){
                //q = std::complex<T>(0.0F, 0.0F);
                q.x = 0.0f;
                q.y = 0.0f;

                for(i=k1; i<n; i++){
                    //q += a(k,i) * v(i,j);
                    q.x += a[k*n + i].x * v[i*n + j].x;
                    q.x -= a[k*n + i].y * v[i*n + j].y;
                    q.y += a[k*n + i].x * v[i*n + j].y;
                    q.y += a[k*n + i].y * v[i*n + j].x;
                }

                //w = sqrt(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y);
                //w = sqrtf(a[k*n + k1].x * a[k*n + k1].x + a[k*n + k1].y * a[k*n + k1].y); // このループ内でaは更新しないので不要
                //q = q / (abs(a(k,k1)) * c[k1]);
                //q.x = q.x / (w * c[k1]);
                //q.y = q.y / (w * c[k1]);
                q.x = q.x * tmp2;
                q.y = q.y * tmp2;

                for(i=k1; i<n; i++){
                    //v(i,j) -= q * conj(a(k,i));
                    tmp  =  q.x * a[k*n + i].x;
                    tmp +=  q.y * a[k*n + i].y;
                    v[i*n + j].x -= tmp;
                    tmp  = -q.x * a[k*n + i].y;
                    tmp +=  q.y * a[k*n + i].x;
                    v[i*n + j].y -= tmp;
                }
            }
        }
    } //if(nv > 0 && n > 1)
    } //for(k=0; k<pslength; k++)

}
#endif

//gpu_Svd(tmp_Rxx, d_REigenValue, d_TempCalc4, d_TempCalc3,
//    localize_music_info.tf_channel_num, localize_music_info.tf_channel_num,
//    UsesFreq, pslength,
//    bb, cc, tt
//    );
void gpu_Svd(cuComplex *aa, float *ss, cuComplex *uu, cuComplex *vv,
    int m, int n,
    int *UsesFreq, int pslength
    )
{
    //int nb_channel = 4;
    //int nb_channel = m;

    //cuComplex *d_uu; //d_TempCalc4
    //cuComplex *d_vv; //d_TempCalc3
    //CUDA_SAFE_CALL(cudaMalloc((void **)&d_uu, sizeof(cuComplex)*nb_channel*nb_channel*pslength));
    //CUDA_SAFE_CALL(cudaMalloc((void **)&d_vv, sizeof(cuComplex)*nb_channel*nb_channel*pslength));

    //float *d_REigenValue;
    //d_REigenValue = (float *)malloc(sizeof(float) * nb_channel * pslength);

#if 1
    //float *d_bb; 
    //float *d_cc; 
    //float *d_tt; 
    //float *d_ss; 
    //float *d_eps; 
    //bb = (float *)malloc(sizeof(float)*MAX_CH_NUM*pslength);
    //cc = (float *)malloc(sizeof(float)*MAX_CH_NUM*pslength);
    //tt = (float *)malloc(sizeof(float)*MAX_CH_NUM*pslength);
    //CUDA_SAFE_CALL(cudaMalloc((void **)&d_bb, sizeof(float)*MAX_CH_NUM*pslength));
    //CUDA_SAFE_CALL(cudaMalloc((void **)&d_cc, sizeof(float)*MAX_CH_NUM*pslength));
    //CUDA_SAFE_CALL(cudaMalloc((void **)&d_tt, sizeof(float)*MAX_CH_NUM*pslength));
    //CUDA_SAFE_CALL(cudaMalloc((void **)&d_ss, sizeof(float)*MAX_CH_NUM*pslength));
    //CUDA_SAFE_CALL(cudaMalloc((void **)&d_eps, sizeof(float)*pslength));

    //CUDA_SAFE_CALL(cudaMemset(d_bb, 0, sizeof(float)*MAX_CH_NUM*pslength));
    //CUDA_SAFE_CALL(cudaMemset(d_cc, 0, sizeof(float)*MAX_CH_NUM*pslength));
    //CUDA_SAFE_CALL(cudaMemset(d_tt, 0, sizeof(float)*MAX_CH_NUM*pslength));

    //float *h_eps; 
    //h_eps = (float *)malloc(sizeof(float)*pslength);
#endif

//void cpu_Svd1(cuComplex *aa, int m, int n,
//    int *UsesFreq, int pslength,
//    float *bb, float *cc
//    )
    //[out] a, c, b
#if 0
    cpu_Svd1(aa, m, n, UsesFreq, pslength,
        bb, cc
        );
#else
    int calc_freq = g_upper- g_lower;

    dim3 block(1, 1);
    //dim3 grid(pslength, 1);
    dim3 grid(calc_freq, 1);
    //dim3 block(pslength, 1);
    //dim3 grid(1, 1);
    //gpu_Svd1<<<grid, block>>>(d_R, m, n, d_UsesFreq, pslength,
    //    d_bb, d_cc
    //    );

    //[in] R
    //[out] b c
    gpu_Svd1_1<<<grid, block>>>(aa, m, n, d_UsesFreq, pslength,
        d_bb, d_cc, g_lower
        );

    //dim3 block2(1, 1);
    dim3 block2(n, 1);
    dim3 grid2(calc_freq, 1);

    //[in] b c
    //[out] s t eps
    gpu_Svd2<<<grid2, block2>>>(m, n, d_UsesFreq, pslength,
        d_bb, d_cc, ss, d_tt, g_lower, d_eps
        );


    dim3 block3(n, m);
    dim3 grid3(calc_freq, 1);

    //[out] u, v
    gpu_Svd3<<<grid3, block3>>>(uu, vv, m, n,
        d_UsesFreq, pslength,
        g_lower
        );

    //[out] a, u, v, t, s
    gpu_Svd4<<<grid, block>>>(aa, ss, uu, vv,
        m, n,
        d_UsesFreq, pslength,
        //bb, cc, tt,
        d_tt,
        d_eps,
        g_lower
        );

    //[out] a, u, v, s
    gpu_Svd5<<<grid, block>>>(aa, ss, uu, vv,
        m, n,
        d_UsesFreq, pslength,
        g_lower
        );

    //[out] a, u, v
    gpu_Svd6<<<grid, block>>>(aa, uu, vv,
        m, n,
        d_UsesFreq, pslength,
        d_bb, d_cc,
        g_lower
        );

//void gpu_Svd6(cuComplex *aa, cuComplex *uu, cuComplex *vv,
//    int m, int n,
//    int *UsesFreq, int pslength,
//    float *bb, float *cc,
//    int st_freq
//    )



    //CUDA_SAFE_CALL(cudaMalloc((void **)&d_R, sizeof(cuComplex)*pslength*nb_channel*nb_channel));
    //CUDA_SAFE_CALL(cudaMemcpy(aa, d_R, sizeof(cuComplex)*pslength*nb_channel*nb_channel, cudaMemcpyDeviceToHost));
    //CUDA_SAFE_CALL(cudaMemcpy(cc, d_cc, sizeof(float)*MAX_CH_NUM*pslength, cudaMemcpyDeviceToHost));
    //CUDA_SAFE_CALL(cudaMemcpy(bb, d_bb, sizeof(float)*MAX_CH_NUM*pslength, cudaMemcpyDeviceToHost));

    // 2
    //CUDA_SAFE_CALL(cudaMemcpy(ss, d_ss, sizeof(float)*MAX_CH_NUM*pslength, cudaMemcpyDeviceToHost));
    //CUDA_SAFE_CALL(cudaMemcpy(tt, d_tt, sizeof(float)*MAX_CH_NUM*pslength, cudaMemcpyDeviceToHost));
    //CUDA_SAFE_CALL(cudaMemcpy(h_eps, d_eps, sizeof(float)*pslength, cudaMemcpyDeviceToHost));

    // 3
    //CUDA_SAFE_CALL(cudaMemcpy(uu, d_uu, sizeof(cuComplex)*nb_channel*nb_channel*pslength, cudaMemcpyDeviceToHost));
    //CUDA_SAFE_CALL(cudaMemcpy(vv, d_vv, sizeof(cuComplex)*nb_channel*nb_channel*pslength, cudaMemcpyDeviceToHost));

    // 4
    //[out] a, u, v, t, s

    // 5
    //[out] a, u, v, s

    //for(int kk=0; kk<pslength; kk++){
    //    if(!UsesFreq[kk]){ continue; }
    //    cuComplex *p_uu = &uu[kk*nb_channel*nb_channel];
    //    cuComplex *p_vv = &vv[kk*nb_channel*nb_channel];
    //
    //    for(int jj=0; jj<nb_channel; jj++){
    //        for(int ii=0; ii<nb_channel; ii++){
    //            printf("uu[%d][%d][%d] = %f, %f\n", kk, jj, ii, 
    //                p_uu[jj*nb_channel + ii].x,
    //                p_uu[jj*nb_channel + ii].y);
    //        }
    //    }
    //}
    //exit(0);
#endif
    //cpu_Svd_QR(aa, ss, uu, vv,
    //    m, n,
    //    UsesFreq, pslength,
    //    //bb, cc, tt,
    //    tt,
    //    h_eps
    //    );

    //cpu_Svd2(aa, ss, uu, vv,
    //    m, n,
    //    UsesFreq, pslength,
    //    bb, cc, tt,
    //    h_eps
    //    );


    //CUDA_SAFE_CALL(cudaDeviceSynchronize());
}

__global__
//void _gpu_SortEigFvecAscending(float *ai, COMPLEX_FLOAT **bi, float *af, COMPLEX_FLOAT **bf)
//void _gpu_SortEigFvecAscending(float *ai, cuComplex *bi, float *af, cuComplex *bf,
void _gpu_SortEigFvecAscending(float *aai, cuComplex *bbi, float *aaf, cuComplex *bbf,
    int m, int nb_channel, int pslength, int st_freq)
{
    int i, j, j_next;
    //int m;
    int index[16];
    int i_tmp;
    float f_tmp;

    float *ai;
    float *af;
    cuComplex *bi;
    cuComplex *bf;

    int k;
    k = blockIdx.x + st_freq;

    if(k>=pslength) return;

    ai = &aai[k*m];
    af = &aaf[k*m];
    bi = &bbi[k*m*m];
    bf = &bbf[k*m*m];

    for(i=0; i<m; i++){
        af[i] = ai[i];
        index[i] = i;
    }

    for(i=m-1; i>=1; i--){
        for(j=0, j_next=1; j<i; j++, j_next++){
            if(af[j] > af[j_next]){
                f_tmp = af[j];
                af[j] = af[j_next];
                af[j_next] = f_tmp;

                i_tmp = index[j];
                index[j] = index[j_next];
                index[j_next] = i_tmp;
            }
        }
    }

    for(i=0; i<m; i++){
        for(j=0; j<m; j++){
            //bf[i][j] = bi[i][index[j]];
            bf[i*m + j] = bi[i*m + index[j]];
        }
    }

}

void gpu_SortEigFvecAscending(float *ai, cuComplex *bi, float *af, cuComplex *bf,
    int m, int nb_channel, int pslength)
{

    int calc_freq = g_upper- g_lower;

    dim3 block(1, 1);
    dim3 grid(calc_freq, 1);
    _gpu_SortEigFvecAscending<<<grid, block>>>(ai, bi, af, bf,
        m, nb_channel, pslength, g_lower);
//void _gpu_SortEigFvecAscending(float *aai, cuComplex *bbi, float *aaf, cuComplex *bbf,
//    int m, int nb_channel, int pslength, int st_freq)
}

