/*
 * Copyright 1993-2010 NVIDIA Corporation.  All rights reserved.
 *
 * NVIDIA Corporation and its licensors retain all intellectual property and 
 * proprietary rights in and to this software and related documentation. 
 * Any use, reproduction, disclosure, or distribution of this software 
 * and related documentation without an express license agreement from
 * NVIDIA Corporation is strictly prohibited.
 *
 * Please refer to the applicable NVIDIA end user license agreement (EULA) 
 * associated with this source code for terms and conditions that govern 
 * your use of this NVIDIA software.
 * 
 */
 
#ifndef __REDUCTION_H__
#define __REDUCTION_H__

/* #include<cuda.h> */

/* #if define(__cplusplus) */
/* extern "C" { */
/* #endif */
enum ReduceType
    {
        REDUCE_INT,
        REDUCE_FLOAT,
        REDUCE_DOUBLE
    };
    
template <class T>
T reduceCPU(T *data, int size);
template <class T>
T* sum_reduce(T* d_idata, int size, int maxThreads=256, int whichKernel=6, int maxBlocks=64);

template <class T>
void reduce_sum(int size, int threads, int blocks, 
                int whichKernel, T *d_idata, T *d_odata);

template <class T>
void reduce6_sum(int size, int threads, int blocks, 
                T *d_idata, T *d_odata);
template <class T>
void reduce6_min(int size, int threads, int blocks, 
                T *d_idata, T *d_odata);
template <class T>
void reduce6_max(int size, int threads, int blocks, 
                T *d_idata, T *d_odata);

double* sum_reduce6_double(double* p_arr, int n, int maxThreads, int maxBlocks);

int* sum_reduce6_int(int* p_arr, int n, int maxThreads, int maxBlocks) ;

float* sum_reduce6_float(float* p_arr, int n, int maxThreads, int maxBlocks) ;

void getNumBlocksAndThreads(int whichKernel, int n, int maxBlocks, int maxThreads, int &blocks, int &threads);

void getNumBlocksAndThreads_6(int n, int maxBlocks, int maxThreads, int &blocks, int &threads);

extern "C" double sum_reduce_double_2host_tesla(double* p_arr, int n, double* d_odata) ;
extern "C" double sum_reduce_double_2host_tesla_test(double* p_arr, int n, double* d_odata) ;
extern "C" double sum_reduce_double_2host_fermi(double* p_arr, int n) ;
extern "C" double min_double_2host_tesla(double* d_idata, int size, double*);
extern "C" double max_double_2host_tesla(double* d_idata, int size, double*);
extern "C" double reduceCPU_double(double *data, int size);

extern "C" double* init_double_tesla();
extern "C" void finalize_double_tesla(double * d_idata);

/* #if define(__cplusplus) */
/* } */
/* #endif */

#endif
