#include <gtest/gtest.h>

#include "MatlabReader.h"
#include "CudaMatrix.h"
#include "Matrix.h"
#include "TestUtility.h"

#include "Function1D.h"
#include "Function1D.cuh"

class Function1D_Cuda_Test:public ::testing::Test
{
protected:
    static void SetUpFunction1DCudaTester(){

    }
    static void TearDownTestCase(){
    }
    void SetUp(){
    }
    void TearDown(){
    }

};

TEST_F(Function1D_Cuda_Test, complex)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1,2,3,4,5,6,7,8}, 2,2,2);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::complex(hostMatrix);
    auto result2 = Aurora::complex(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), 8);
    EXPECT_EQ(result2.getValueType(), Aurora::Complex);
    for(size_t i=0; i<result1.getDataSize() * 2; ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }

    Aurora::Matrix hostMatrix2 = Aurora::Matrix::fromRawData(new float[8]{1,2,3,4,5,6,7,8}, 2,2,2);
    Aurora::CudaMatrix deviceMatrix2 = hostMatrix.toDeviceMatrix();
    result2 = Aurora::complex(deviceMatrix, deviceMatrix2).toHostMatrix();
    for(size_t i=0; i<result2.getDataSize(); ++i)
    {
        EXPECT_EQ(hostMatrix[i], result2[2 * i]);
        EXPECT_EQ(hostMatrix2[i], result2[2 * i + 1]);
    }
}

TEST_F(Function1D_Cuda_Test, real)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1,2,3,4,5,6,7,8}, 2,2,1,Aurora::Complex);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::real(hostMatrix);
    auto result2 = Aurora::real(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), 4);
    EXPECT_EQ(result2.getValueType(), Aurora::Normal);
    for(size_t i=0; i<result1.getDataSize(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, imag)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1,2,3,4,5,6,7,8}, 2,2,1,Aurora::Complex);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::imag(hostMatrix);
    auto result2 = Aurora::imag(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), 4);
    EXPECT_EQ(result2.getValueType(), Aurora::Normal);
    for(size_t i=0; i<result1.getDataSize(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, ceil)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}, 2,4);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::ceil(hostMatrix);
    auto result2 = Aurora::ceil(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), 8);
    EXPECT_EQ(result2.getValueType(), Aurora::Normal);
    for(size_t i=0; i<result1.getDataSize(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }

    hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}, 2,2,1,Aurora::Complex);
    deviceMatrix = hostMatrix.toDeviceMatrix();
    result1 = Aurora::ceil(hostMatrix);
    result2 = Aurora::ceil(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), 4);
    EXPECT_EQ(result2.getValueType(), Aurora::Complex);
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, round)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}, 2,4);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::round(hostMatrix);
    auto result2 = Aurora::round(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), 8);
    EXPECT_EQ(result2.getValueType(), Aurora::Normal);
    for(size_t i=0; i<result1.getDataSize(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }

    hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}, 2,2,1,Aurora::Complex);
    deviceMatrix = hostMatrix.toDeviceMatrix();
    result1 = Aurora::round(hostMatrix);
    result2 = Aurora::round(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), 4);
    EXPECT_EQ(result2.getValueType(), Aurora::Complex);
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, floor)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}, 2,4);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::floor(hostMatrix);
    auto result2 = Aurora::floor(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), 8);
    EXPECT_EQ(result2.getValueType(), Aurora::Normal);
    for(size_t i=0; i<result1.getDataSize(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }

    hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}, 2,2,1,Aurora::Complex);
    deviceMatrix = hostMatrix.toDeviceMatrix();
    result1 = Aurora::floor(hostMatrix);
    result2 = Aurora::floor(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), 4);
    EXPECT_EQ(result2.getValueType(), Aurora::Complex);
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, sqrt)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}, 2,4);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::sqrt(hostMatrix);
    auto result2 = Aurora::sqrt(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), 8);
    EXPECT_EQ(result2.getValueType(), Aurora::Normal);
    for(size_t i=0; i<result1.getDataSize(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }

    hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}, 2,2,1,Aurora::Complex);
    deviceMatrix = hostMatrix.toDeviceMatrix();
    result1 = Aurora::sqrt(hostMatrix);
    result2 = Aurora::sqrt(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), result1.getDataSize());
    EXPECT_EQ(result2.getValueType(), result1.getValueType());
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, abs)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[10000]{0}, 1,10000);
    for (size_t i = 0; i < 10000; i++)
    {
        hostMatrix[i]=i;
    }
    
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::abs(hostMatrix);
    auto result2 = Aurora::abs(deviceMatrix).toHostMatrix();
    // EXPECT_EQ(result2.getDataSize(), 8);
    EXPECT_EQ(result2.getValueType(), Aurora::Normal);

    for(size_t i=0; i<result1.getDataSize(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);

    }

    hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}, 2,2,1,Aurora::Complex);
    deviceMatrix = hostMatrix.toDeviceMatrix();
    result1 = Aurora::abs(hostMatrix);
    result2 = Aurora::abs(deviceMatrix).toHostMatrix();

    EXPECT_EQ(result2.getDataSize(), 4);
    EXPECT_EQ(result2.getValueType(), Aurora::Normal);

    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, sign)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}, 2,4);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::sign(hostMatrix);
    auto result2 = Aurora::sign(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), 8);
    EXPECT_EQ(result2.getValueType(), Aurora::Normal);
    for(size_t i=0; i<result1.getDataSize(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }

    hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}, 2,2,1,Aurora::Complex);
    deviceMatrix = hostMatrix.toDeviceMatrix();
    result1 = Aurora::sign(hostMatrix);
    result2 = Aurora::sign(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), 4);
    EXPECT_EQ(result2.getValueType(), Aurora::Complex);
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, repmat)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}, 2,4);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::repmat(hostMatrix,3,6);
    auto result2 = Aurora::repmat(deviceMatrix,3,6).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), 8 * 3 * 6);
    EXPECT_EQ(result2.getValueType(), Aurora::Normal);
    for(size_t i=0; i<result1.getDataSize(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }

    hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}, 2,2,1,Aurora::Complex);
    deviceMatrix = hostMatrix.toDeviceMatrix();
    result1 = Aurora::repmat(hostMatrix, 4, 8);
    result2 = Aurora::repmat(deviceMatrix, 4, 8).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), 4 * 4 * 8);
    EXPECT_EQ(result2.getValueType(), Aurora::Complex);
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }

    hostMatrix = Aurora::Matrix::fromRawData(new float[12]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10,11,12}, 3, 4, 1,Aurora::Normal);
    deviceMatrix = hostMatrix.toDeviceMatrix();
    result1 = Aurora::repmat(hostMatrix, 4, 8, 3);
    result2 = Aurora::repmat(deviceMatrix, 4, 8, 3).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), 3 * 4 * 4 * 8 * 3);
    EXPECT_EQ(result2.getValueType(), Aurora::Normal);
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }

    hostMatrix = Aurora::Matrix::fromRawData(new float[12]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10,11,12}, 3, 2, 1,Aurora::Complex);
    deviceMatrix = hostMatrix.toDeviceMatrix();
    result1 = Aurora::repmat(hostMatrix, 4, 8, 3);
    result2 = Aurora::repmat(deviceMatrix, 4, 8, 3).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), 3 * 2 * 4 * 8 * 3);
    EXPECT_EQ(result2.getValueType(), Aurora::Complex);
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, repmat3d)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[12]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9,10,11,12}, 2,3,2);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::repmat3d(hostMatrix,3,6,4);
    auto result2 = Aurora::repmat3d(deviceMatrix,3,6,4).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), result1.getDataSize());
    EXPECT_EQ(result2.getValueType(), Aurora::Normal);
    for(size_t i=0; i<result1.getDataSize(); ++i)
    {
        EXPECT_EQ(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, log)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}, 2,4);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::log(hostMatrix);
    auto result2 = Aurora::log(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), result1.getDataSize());
    EXPECT_EQ(result2.getValueType(), result1.getValueType());
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_FLOAT_AE(result1[i], result2[i]);
    }

    result1 = Aurora::log(hostMatrix,3);
    result2 = Aurora::log(deviceMatrix,3).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), result1.getDataSize());
    EXPECT_EQ(result2.getValueType(), result1.getValueType());
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_FLOAT_AE(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, nanAndFinite)
{
    float n=std::nan("");
    float infinite=std::numeric_limits<float>::infinity();

    float* data = new float[9]{infinite,3,n,2,2,1,4,4,7};
    auto matrix = Aurora::Matrix::fromRawData(data, 9,1,1).toDeviceMatrix();
    auto r = Aurora::isnan(matrix);
    EXPECT_FLOAT_EQ(r.getValue(0),0);
    EXPECT_FLOAT_EQ(r.getValue(1),0);
    EXPECT_FLOAT_EQ(r.getValue(2),1);

    r = Aurora::isfinite(matrix);
    EXPECT_FLOAT_EQ(r.getValue(0),0);
    EXPECT_FLOAT_EQ(r.getValue(1),1);
    EXPECT_FLOAT_EQ(r.getValue(2),0);

    Aurora::nantoval(matrix,1);
    EXPECT_FLOAT_EQ(matrix.getValue(2),1);

    float* data2 = new float[1]{n};
    auto matrix2 = Aurora::Matrix::fromRawData(data2, 1,1,1).toDeviceMatrix();
    r = Aurora::isnan(matrix2);
    EXPECT_FLOAT_EQ(r.getValue(0),1);

    r = Aurora::isfinite(matrix2);
    EXPECT_FLOAT_EQ(r.getValue(0),0);

    Aurora::nantoval(matrix2,1);
    EXPECT_FLOAT_EQ(matrix2.getValue(0),1);
}

TEST_F(Function1D_Cuda_Test, isnanOrfinite)
{
    float *input =  new float[18]{10,2,1,3,4,4,16,3,1,2,15,-2,1,-3,4,-4,1,-3};
    auto ma = Aurora::Matrix::fromRawData(input,18,1,1).toDeviceMatrix();
    Aurora::padding(ma,20,1);
    EXPECT_FLOAT_AE(ma.getValue(19),1);
    EXPECT_FLOAT_AE(ma.getValue(20),1);
    Aurora::padding(ma,10,-1);
    EXPECT_FLOAT_AE(ma.getValue(10),-1);
}

TEST_F(Function1D_Cuda_Test, padding)
{
    float *input =  new float[18]{10,2,1,3,4,4,16,3,1,2,15,-2,1,-3,4,-4,1,-3};
    auto ma = Aurora::Matrix::fromRawData(input,18,1,1).toDeviceMatrix();
    Aurora::padding(ma,20,1);
    EXPECT_FLOAT_AE(ma.getValue(19),1);
    EXPECT_FLOAT_AE(ma.getValue(20),1);
    Aurora::padding(ma,10,-1);
    EXPECT_FLOAT_AE(ma.getValue(10),-1);
}

TEST_F(Function1D_Cuda_Test, not)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[8]{-1.1,2.2,-3.3,0,-5.5,6.6,0.7,-0.8}, 2,4);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::auroraNot(hostMatrix);
    auto result2 = Aurora::auroraNot(deviceMatrix);
    EXPECT_EQ(result2.getDataSize(), result1.getDataSize());
    EXPECT_EQ(result2.getValueType(), result1.getValueType());
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_FLOAT_AE(result1[i], result2.getValue(i));
    }

    result1 = Aurora::auroraNot(hostMatrix);
    result2 = Aurora::auroraNot(hostMatrix.toDeviceMatrix());
    EXPECT_EQ(result2.getDataSize(), result1.getDataSize());
    EXPECT_EQ(result2.getValueType(), result1.getValueType());
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_FLOAT_AE(result1[i], result2.getValue(i));
    }
}


TEST_F(Function1D_Cuda_Test, compareSet)
{
    Aurora::Matrix A =Aurora::Matrix::fromRawData(new float[9]{0},9,1);
    Aurora::Matrix B =Aurora::Matrix::fromRawData(new float[9]{0},9,1);
    for (int i = 0; i < 9; ++i) {
        A[i]=(float)(i-3);
        B[i]=(float)(i+2);
    }
    {

        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,0,0,Aurora::LT);
        compareSet(A,0,0,Aurora::LT);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    {

        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        auto A = dA.toHostMatrix();
        compareSet(dA,0,0,Aurora::GT);
        compareSet(A,0,0,Aurora::GT);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    {

        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        auto A = dA.toHostMatrix();
        compareSet(dA,-1,0,Aurora::EQ);
        compareSet(A,-1,0,Aurora::EQ);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    {

        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        auto A = dA.toHostMatrix();
        compareSet(dA,-1,0,Aurora::NE);
        compareSet(A,-1,0,Aurora::NE);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    {

        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        auto A = dA.toHostMatrix();
        compareSet(dA,-1,0,Aurora::NL);
        compareSet(A,-1,0,Aurora::NL);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    {

        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        auto A = dA.toHostMatrix();
        compareSet(dA,-1,0,Aurora::NG);
        compareSet(A,-1,0,Aurora::NG);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //Function m m v v
    //NE
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,4,-1,Aurora::NE);
        compareSet(A,B,4,-1,Aurora::NE);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //EQ
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,4,-1,Aurora::EQ);
        compareSet(A,B,4,-1,Aurora::EQ);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //GT
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,1,-1,Aurora::GT);
        compareSet(A,B,1,-1,Aurora::GT);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //LT
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,3,-1,Aurora::LT);
        compareSet(A,B,3,-1,Aurora::LT);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //NL
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,3,-1,Aurora::NL);
        compareSet(A,B,3,-1,Aurora::NL);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //LT
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,3,-1,Aurora::NG);
        compareSet(A,B,3,-1,Aurora::NG);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //Function m m v 
    //NE
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,-1,Aurora::NE);
        compareSet(A,B,-1,Aurora::NE);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //EQ
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,-1,Aurora::EQ);
        compareSet(A,B,-1,Aurora::EQ);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //GT
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,-1,Aurora::GT);
        compareSet(A,B,-1,Aurora::GT);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //LT
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,-1,Aurora::LT);
        compareSet(A,B,-1,Aurora::LT);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //NL
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,-1,Aurora::NL);
        compareSet(A,B,-1,Aurora::NL);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //LT
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,-1,Aurora::NG);
        compareSet(A,B,-1,Aurora::NG);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
        //Function m m v v
    //NE
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,4,-1,Aurora::NE);
        compareSet(A,B,4,-1,Aurora::NE);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //EQ
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,4,-1,Aurora::EQ);
        compareSet(A,B,4,-1,Aurora::EQ);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //GT
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,1,-1,Aurora::GT);
        compareSet(A,B,1,-1,Aurora::GT);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //LT
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,3,-1,Aurora::LT);
        compareSet(A,B,3,-1,Aurora::LT);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //NL
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,3,-1,Aurora::NL);
        compareSet(A,B,3,-1,Aurora::NL);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //LT
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,dB,3,-1,Aurora::NG);
        compareSet(A,B,3,-1,Aurora::NG);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //Function m v m
    //NE
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,-1,dB,Aurora::NE);
        compareSet(A,-1,B,Aurora::NE);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //EQ
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,-1,dB,Aurora::EQ);
        compareSet(A,-1,B,Aurora::EQ);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //GT
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,-1,dB,Aurora::GT);
        compareSet(A,-1,B,Aurora::GT);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //LT
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,-1,dB,Aurora::LT);
        compareSet(A,-1,B,Aurora::LT);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //NL
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,-1,dB,Aurora::NL);
        compareSet(A,-1,B,Aurora::NL);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
    //LT
    {
        Aurora::CudaMatrix dB = B.toDeviceMatrix();
        Aurora::CudaMatrix dA = A.toDeviceMatrix();
        compareSet(dA,-1,dB,Aurora::NG);
        compareSet(A,-1,B,Aurora::NG);
        for (size_t i = 0; i < 9; i++)
        {
            EXPECT_EQ(dA.getValue(i), A[i]);
        }
    }
}

TEST_F(Function1D_Cuda_Test, exp)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}, 2,4);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::exp(hostMatrix);
    auto result2 = Aurora::exp(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), result1.getDataSize());
    EXPECT_EQ(result2.getValueType(), result1.getValueType());
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_FLOAT_AE(result1[i], result2[i]);
    }

    hostMatrix = Aurora::Matrix::fromRawData(new float[12]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10,11,12}, 3, 2, 1,Aurora::Complex);
    deviceMatrix = hostMatrix.toDeviceMatrix();
    result1 = Aurora::exp(hostMatrix);
    result2 = Aurora::exp(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), result1.getDataSize());
    EXPECT_EQ(result2.getValueType(), result1.getValueType());
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_FLOAT_AE(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, mod)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[8]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8}, 2,4);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::mod(hostMatrix, 2);
    auto result2 = Aurora::mod(deviceMatrix, 2).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), result1.getDataSize());
    EXPECT_EQ(result2.getValueType(), result1.getValueType());
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_FLOAT_AE(result1[i], result2[i]);
    }

    result1 = Aurora::mod(hostMatrix, 3);
    result2 = Aurora::mod(deviceMatrix, 3).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), result1.getDataSize());
    EXPECT_EQ(result2.getValueType(), result1.getValueType());
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_FLOAT_AE(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, acos)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[8]{0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8}, 2,4);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::acos(hostMatrix);
    auto result2 = Aurora::acos(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), result1.getDataSize());
    EXPECT_EQ(result2.getValueType(), result1.getValueType());
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_FLOAT_AE(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, acosd)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[8]{0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8}, 2,4);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::acosd(hostMatrix);
    auto result2 = Aurora::acosd(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), result1.getDataSize());
    EXPECT_EQ(result2.getValueType(), result1.getValueType());
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_FLOAT_AE(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, conj)
{
    Aurora::Matrix hostMatrix = Aurora::Matrix::fromRawData(new float[8]{0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8}, 2,4);
    Aurora::CudaMatrix deviceMatrix = hostMatrix.toDeviceMatrix();
    
    auto result1 = Aurora::conj(hostMatrix);
    auto result2 = Aurora::conj(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), result1.getDataSize());
    EXPECT_EQ(result2.getValueType(), result1.getValueType());
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_FLOAT_AE(result1[i], result2[i]);
    }

    hostMatrix = Aurora::Matrix::fromRawData(new float[12]{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10,11,12}, 3, 2, 1,Aurora::Complex);
    deviceMatrix = hostMatrix.toDeviceMatrix();
    result1 = Aurora::conj(hostMatrix);
    result2 = Aurora::conj(deviceMatrix).toHostMatrix();
    EXPECT_EQ(result2.getDataSize(), result1.getDataSize());
    EXPECT_EQ(result2.getValueType(), result1.getValueType());
    for(size_t i=0; i<result1.getDataSize() * result1.getValueType(); ++i)
    {
        EXPECT_FLOAT_AE(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, norm) {
    //1Dim
    float *data = new float[3]{1,2,-3};
    auto matrix = Aurora::Matrix::fromRawData(data, 3);
    auto deviceMatrix = matrix.toDeviceMatrix();
    auto result = Aurora::norm(matrix.toDeviceMatrix(), Aurora::NormMethod::Norm1);
    EXPECT_FLOAT_AE(result,6);
    result = Aurora::norm(deviceMatrix,Aurora::NormMethod::Norm2);
    EXPECT_FLOAT_AE(result,3.74166);
    result = Aurora::norm(deviceMatrix,Aurora::NormMethod::NormF);
    EXPECT_FLOAT_AE(result,3.74166);

    //2Dims
    data = new float[8]{1,2,-3,6,7,9,22.3,-8.6};
    matrix = Aurora::Matrix::fromRawData(data, 4,2);
    deviceMatrix = matrix.toDeviceMatrix();
    result = Aurora::norm(deviceMatrix,Aurora::NormMethod::Norm1);
    EXPECT_FLOAT_AE(result,46.9);
    result = Aurora::norm(deviceMatrix,Aurora::NormMethod::Norm2);
    EXPECT_FLOAT_AE(result,26.7284);
    result = Aurora::norm(deviceMatrix,Aurora::NormMethod::NormF);
    EXPECT_FLOAT_AE(result,27.4089);

    //1Dim Complex
    data = new float[6]{1,2,-3,4,5,-6};
    matrix = Aurora::Matrix::fromRawData(data, 3,1,1,Aurora::Complex);
    deviceMatrix = matrix.toDeviceMatrix();
    result = Aurora::norm(deviceMatrix,Aurora::NormMethod::Norm1);
    EXPECT_FLOAT_AE(result,15.0463);
    result = Aurora::norm(deviceMatrix,Aurora::NormMethod::Norm2);
    EXPECT_FLOAT_AE(result,9.5394);
    result = Aurora::norm(deviceMatrix,Aurora::NormMethod::NormF);
    EXPECT_FLOAT_AE(result,9.5394);

    //2Dims Complex
    data = new float[12]{1,2,-3,4,5,-6,7,8,9,22,24,25};
    matrix = Aurora::Matrix::fromRawData(data, 3,2,1,Aurora::Complex);
    deviceMatrix = matrix.toDeviceMatrix();
    result = Aurora::norm(deviceMatrix,Aurora::NormMethod::Norm1);
    EXPECT_FLOAT_AE(result,69.0553);
    //not support
    //result = Aurora::norm(matrix,Aurora::NormMethod::Norm2);
    //EXPECT_FLOAT_AE(result,43.5314);
    result = Aurora::norm(deviceMatrix,Aurora::NormMethod::NormF);
    EXPECT_FLOAT_AE(result,44.3847);
}

TEST_F(Function1D_Cuda_Test, transpose) {
    float *data = new float[6]{1,2,3,4,5,6};
    auto matrix = Aurora::Matrix::fromRawData(data, 3,2).toDeviceMatrix();
    auto result = Aurora::transpose(matrix).toHostMatrix();
    
    EXPECT_FLOAT_EQ(result.getData()[0],1);
    EXPECT_FLOAT_EQ(result.getData()[1],4);
    EXPECT_FLOAT_EQ(result.getData()[2],2);
    EXPECT_FLOAT_EQ(result.getData()[3],5);
    EXPECT_FLOAT_EQ(result.getData()[4],3);
    EXPECT_FLOAT_EQ(result.getData()[5],6);
    EXPECT_FLOAT_EQ(result.getDimSize(0),2);
    EXPECT_FLOAT_EQ(result.getDimSize(1),3);

    data = new float[12]{1,2,3,4,5,6,7,8,9,10,11,12};
    matrix = Aurora::Matrix::fromRawData(data, 3,2,1,Aurora::Complex).toDeviceMatrix();
    result = Aurora::transpose(matrix).toHostMatrix();
    EXPECT_FLOAT_EQ(result.getData()[0],1);
    EXPECT_FLOAT_EQ(result.getData()[1],2);
    EXPECT_FLOAT_EQ(result.getData()[2],7);
    EXPECT_FLOAT_EQ(result.getData()[3],8);
    EXPECT_FLOAT_EQ(result.getData()[4],3);
    EXPECT_FLOAT_EQ(result.getData()[5],4);
    EXPECT_FLOAT_EQ(result.getData()[6],9);
    EXPECT_FLOAT_EQ(result.getData()[7],10);
    EXPECT_FLOAT_EQ(result.getData()[8],5);
    EXPECT_FLOAT_EQ(result.getData()[9],6);
    EXPECT_FLOAT_EQ(result.getData()[10],11);
    EXPECT_FLOAT_EQ(result.getData()[11],12);
    EXPECT_FLOAT_EQ(result.getDimSize(0),2);
    EXPECT_FLOAT_EQ(result.getDimSize(1),3);
    EXPECT_FLOAT_EQ(result.getDimSize(0),2);
    EXPECT_FLOAT_EQ(result.getDimSize(1),3);
}

TEST_F(Function1D_Cuda_Test, horzcat) {
    float *data1 = new float[6]{1,2,3,4,5,6};
    auto matrix1 = Aurora::Matrix::fromRawData(data1, 3,2).toDeviceMatrix();
    float *data2 = new float[9]{7,8,9,10,11,12,13,14,15};
    auto matrix2 = Aurora::Matrix::fromRawData(data2, 3,3).toDeviceMatrix();
    auto result = Aurora::horzcat(matrix1,matrix2).toHostMatrix();
    EXPECT_FLOAT_EQ(result.getData()[0],1);
    EXPECT_FLOAT_EQ(result.getData()[1],2);
    EXPECT_FLOAT_EQ(result.getData()[10],11);
    EXPECT_FLOAT_EQ(result.getData()[14],15);
    EXPECT_FLOAT_EQ(result.getDimSize(0),3);
    EXPECT_FLOAT_EQ(result.getDimSize(1),5);

    data1 = new float[6]{1,2,3,4,5,6};
    matrix1 = Aurora::Matrix::fromRawData(data1, 3,1,1,Aurora::Complex).toDeviceMatrix();
    data2 = new float[6]{7,8,9,10,11,12};
    matrix2 = Aurora::Matrix::fromRawData(data2, 3,1,1,Aurora::Complex).toDeviceMatrix();
    result = Aurora::horzcat(matrix1,matrix2).toHostMatrix();
    EXPECT_FLOAT_EQ(result.getData()[0],1);
    EXPECT_FLOAT_EQ(result.getData()[1],2);
    EXPECT_FLOAT_EQ(result.getData()[8],9);
    EXPECT_FLOAT_EQ(result.getData()[9],10);
    EXPECT_FLOAT_EQ(result.getDimSize(0),3);
    EXPECT_FLOAT_EQ(result.getDimSize(1),2);
}

TEST_F(Function1D_Cuda_Test, vertcat) {
    float *data1 = new float[6]{1,2,3,4,5,6};
    auto matrix1 = Aurora::Matrix::fromRawData(data1, 2,3).toDeviceMatrix();
    float *data2 = new float[9]{7,8,9,10,11,12,13,14,15};
    auto matrix2 = Aurora::Matrix::fromRawData(data2, 3,3).toDeviceMatrix();
    auto result = Aurora::vertcat(matrix1,matrix2).toHostMatrix();
    EXPECT_FLOAT_EQ(result.getData()[0],1);
    EXPECT_FLOAT_EQ(result.getData()[1],2);
    EXPECT_FLOAT_EQ(result.getData()[10],5);
    EXPECT_FLOAT_EQ(result.getData()[14],15);
    EXPECT_FLOAT_EQ(result.getDimSize(0),5);
    EXPECT_FLOAT_EQ(result.getDimSize(1),3);

    data1 = new float[6]{1,2,3,4,5,6};
    matrix1 = Aurora::Matrix::fromRawData(data1, 3,1,1,Aurora::Complex).toDeviceMatrix();
    data2 = new float[6]{7,8,9,10,11,12};
    matrix2 = Aurora::Matrix::fromRawData(data2, 3,1,1,Aurora::Complex).toDeviceMatrix();
    result = Aurora::vertcat(matrix1,matrix2).toHostMatrix();
    EXPECT_FLOAT_EQ(result.getData()[0],1);
    EXPECT_FLOAT_EQ(result.getData()[1],2);
    EXPECT_FLOAT_EQ(result.getData()[8],9);
    EXPECT_FLOAT_EQ(result.getData()[9],10);
    EXPECT_FLOAT_EQ(result.getDimSize(0),6);
    EXPECT_FLOAT_EQ(result.getDimSize(1),1);
}

TEST_F(Function1D_Cuda_Test, vecnorm) {
    //1Dim
    float *data = new float[3]{1,2,-3};
    auto matrix = Aurora::Matrix::fromRawData(data, 3).toDeviceMatrix();
    auto result = Aurora::vecnorm(matrix,Aurora::NormMethod::Norm1,1).toHostMatrix();
    EXPECT_FLOAT_AE(result.getData()[0],6);
    result = Aurora::vecnorm(matrix,Aurora::NormMethod::Norm2,1).toHostMatrix();
    EXPECT_FLOAT_AE(result.getData()[0],3.74166);

    //2Dims
    data = new float[8]{1,2,-3,6,7,9,22.3,-8.6};
    matrix = Aurora::Matrix::fromRawData(data, 4,2).toDeviceMatrix();
    result = Aurora::vecnorm(matrix,Aurora::NormMethod::Norm1,1).toHostMatrix();
    EXPECT_FLOAT_AE(result.getData()[0],12);
    EXPECT_FLOAT_AE(result.getData()[1],46.9);
    result = Aurora::vecnorm(matrix,Aurora::NormMethod::Norm2,1).toHostMatrix();
    EXPECT_FLOAT_AE(result.getData()[0],7.0711);
    EXPECT_FLOAT_AE(result.getData()[1],26.4811);

    //1Dim Complex
    data = new float[6]{1,2,-3,4,5,-6};
    matrix = Aurora::Matrix::fromRawData(data, 3,1,1,Aurora::Complex).toDeviceMatrix();
    result = Aurora::vecnorm(matrix,Aurora::NormMethod::Norm1,1).toHostMatrix();
    EXPECT_FLOAT_AE(result.getData()[0],15.0463);
    result = Aurora::vecnorm(matrix,Aurora::NormMethod::Norm2,1).toHostMatrix();
    EXPECT_FLOAT_AE(result.getData()[0],9.5394);

    //2Dims Complex
    data = new float[12]{1,2,-3,4,5,-6,7,8,9,22,24,25};
    matrix = Aurora::Matrix::fromRawData(data, 3,2,1,Aurora::Complex).toDeviceMatrix();
    result = Aurora::vecnorm(matrix,Aurora::NormMethod::Norm1,1).toHostMatrix();
    EXPECT_FLOAT_AE(result.getData()[0],15.0463);
    EXPECT_FLOAT_AE(result.getData()[1],69.0553);
    result = Aurora::vecnorm(matrix,Aurora::NormMethod::Norm2,1).toHostMatrix();
    EXPECT_FLOAT_AE(result.getData()[0],9.5394);
    EXPECT_FLOAT_AE(result.getData()[1],43.3474);
}

TEST_F(Function1D_Cuda_Test, linspace) {
    auto result1 = Aurora::linspace(-5,5,7);
    auto result2 = Aurora::linspaceCuda(-5,5,7).toHostMatrix();
    EXPECT_FLOAT_EQ(result1.getDataSize(), result2.getDataSize());
    for(int i=0; i<result1.getDataSize(); ++i)
    {
        EXPECT_FLOAT_AE(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, auroraUnion) {
    float* data1 = new float[9]{3,3,2,2,2,1,4,4,7};
    auto matrix1 = Aurora::Matrix::fromRawData(data1, 9,1,1);
    float* data2 = new float[8]{6,6,7,7,8,1,2};
    auto matrix2 = Aurora::Matrix::fromRawData(data2, 7,1,1);

    auto result1 = Aurora::auroraUnion(matrix1, matrix2);
    auto result2 = Aurora::auroraUnion(matrix1.toDeviceMatrix(), matrix2.toDeviceMatrix()).toHostMatrix();
    EXPECT_FLOAT_AE(result1.getDataSize(), result2.getDataSize());
    for(int i=0;i<result1.getDataSize();++i)
    {
        EXPECT_FLOAT_AE(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, intersect) {
    float* data1 = new float[9]{3,3,2,2,2,1,4,4,7};
    auto matrix1 = Aurora::Matrix::fromRawData(data1, 9,1,1).toDeviceMatrix();
    float* data2 = new float[8]{6,6,7,7,8,1,2};
    auto matrix2 = Aurora::Matrix::fromRawData(data2, 7,1,1).toDeviceMatrix();

    auto result = Aurora::intersect(matrix1, matrix2).toHostMatrix();
    EXPECT_FLOAT_AE(result.getData()[0],1);
    EXPECT_FLOAT_AE(result.getData()[1],2);
    EXPECT_FLOAT_AE(result.getData()[2],7);

    Aurora::CudaMatrix ia;
    result = Aurora::intersect(matrix1, matrix2, ia).toHostMatrix();
    auto iaHost = ia.toHostMatrix();
    EXPECT_FLOAT_AE(result.getData()[0],1);
    EXPECT_FLOAT_AE(result.getData()[1],2);
    EXPECT_FLOAT_AE(result.getData()[2],7);
    EXPECT_FLOAT_AE(iaHost.getData()[0],6);
    EXPECT_FLOAT_AE(iaHost.getData()[1],3);
    EXPECT_FLOAT_AE(iaHost.getData()[2],9);
}

TEST_F(Function1D_Cuda_Test, reshape) {
    float* data = new float[9]{3,3,2,2,2,1,4,4,7};
    auto matrixHost = Aurora::Matrix::fromRawData(data, 9,1,1);
    auto matrixDevice = matrixHost.toDeviceMatrix();
    auto result = Aurora::reshape(matrixDevice,3,3,1);
    EXPECT_FLOAT_AE(result.getDimSize(0),3);
    EXPECT_FLOAT_AE(result.getDimSize(1),3);
    EXPECT_FLOAT_AE(result.getDimSize(2),1);
    result = Aurora::reshape(matrixDevice,3,1,3);
    EXPECT_FLOAT_AE(result.getDimSize(0),3);
    EXPECT_FLOAT_AE(result.getDimSize(1),1);
    EXPECT_FLOAT_AE(result.getDimSize(2),3);
    result = Aurora::reshape(matrixDevice,1,3,3);
    EXPECT_FLOAT_AE(result.getDimSize(0),1);
    EXPECT_FLOAT_AE(result.getDimSize(1),3);
    EXPECT_FLOAT_AE(result.getDimSize(2),3);
    auto resultHost = result.toHostMatrix();
    for(int i=0; i<9; ++i)
    {
        EXPECT_FLOAT_AE(resultHost[i], data[i]);
    }
}

TEST_F(Function1D_Cuda_Test, xcorr) {
    auto matrixHost1 = Aurora::Matrix::fromRawData(new float[4]{7,8,9,10}, 4,1,1);
    auto matrixHost2 = Aurora::Matrix::fromRawData(new float[4]{2,3,6,7}, 4,1,1);
    auto matrixDevice1 = matrixHost1.toDeviceMatrix();
    auto matrixDevice2 = matrixHost2.toDeviceMatrix();
    auto result = Aurora::xcorr(matrixDevice1,matrixDevice2).toHostMatrix();
    EXPECT_FLOAT_AE(result[0], 49);
    EXPECT_FLOAT_AE(result[1], 98);
    EXPECT_FLOAT_AE(result[2], 132);
    EXPECT_FLOAT_AE(result[3], 162);
    EXPECT_FLOAT_AE(result[4], 103);
    EXPECT_FLOAT_AE(result[5], 48);
    EXPECT_FLOAT_AE(result[6], 20);
}

TEST_F(Function1D_Cuda_Test, deleteColumn) {
    auto matrixHost = Aurora::Matrix::fromRawData(new float[100], 10,10,1);
    for(int i=0;i<100;++i)
    {
        matrixHost[i] = i;
    }
    auto matrixDevice = matrixHost.toDeviceMatrix();
    auto result1 = Aurora::deleteColumn(matrixHost, 26);
    auto result2 = Aurora::deleteColumn(matrixDevice, 26).toHostMatrix();
    EXPECT_FLOAT_AE(result1.getDimSize(0),result2.getDimSize(0));
    EXPECT_FLOAT_AE(result1.getDimSize(1),result2.getDimSize(1));
    EXPECT_FLOAT_AE(result1.getDataSize(),result2.getDataSize());
    for(int i=0;i<result1.getDataSize();++i)
    {
        EXPECT_FLOAT_AE(result1[i], result2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, uniqueByRows) {
    auto matrixHost = Aurora::Matrix::fromRawData(new float[12]{6,2,2,2,4,7,7,7,1,8,9,8},4,3,1,Aurora::Normal);
    Aurora::Matrix indexHost;
    auto matrixDevice = matrixHost.toDeviceMatrix();
    Aurora::CudaMatrix indexDevice;
    auto result1 = Aurora::uniqueByRows(matrixHost, indexHost);
    auto result2 = Aurora::uniqueByRows(matrixDevice, indexDevice).toHostMatrix();
    auto indexResult1 = indexHost;
    auto indexResult2 = indexDevice.toHostMatrix();
    EXPECT_FLOAT_AE(result1.getDimSize(0),result2.getDimSize(0));
    EXPECT_FLOAT_AE(result1.getDimSize(1),result2.getDimSize(1));
    EXPECT_FLOAT_AE(result1.getDataSize(),result2.getDataSize());

    EXPECT_FLOAT_AE(indexResult1.getDimSize(0),indexResult2.getDimSize(0));
    EXPECT_FLOAT_AE(indexResult1.getDimSize(1),indexResult2.getDimSize(1));
    EXPECT_FLOAT_AE(indexResult1.getDataSize(),indexResult2.getDataSize());
    
    for(int i=0;i<result1.getDataSize();++i)
    {
        EXPECT_FLOAT_AE(result1[i], result2[i]);
    }

    for(int i=0;i<indexResult1.getDataSize();++i)
    {
        EXPECT_FLOAT_AE(indexResult1[i], indexResult2[i]);
    }
}

TEST_F(Function1D_Cuda_Test, convertfp16tofloat) {
    MatlabReader m("/home/krad/TestData/convertReal.mat");

    size_t count = 0;
    auto input = m.readint16("input",count);
    auto resultM = Aurora::convertfp16tofloat(input.get(),count,1);
    auto resultC = Aurora::convertfp16tofloatCuda(input.get(),count,1);
    for (size_t i = 0; i<100; i++) {
        
        EXPECT_FLOAT_EQ(resultC.getValue(i), resultM[i])<<",index:"<<i;
    }
}
