#include <CudaMatrixPrivate.cuh>
#include <math.h>
#include <thrust/transform.h>
#include <thrust/complex.h>
#include <thrust/functional.h>
#include <thrust/execution_policy.h>

#include "AuroraDefs.h"
#include "AuroraThrustIterator.cuh"
using namespace thrust::placeholders;

struct PowOp: public thrust::unary_function<float, float>{
    float exponent;
    PowOp(float v):exponent(v) {}
    void setExponent(float v){
        exponent = v;
    }
    
    __host__ __device__
    float operator()(const float& x)  {
        return powf(x, exponent);
    }
};

struct CompareGOp: public thrust::unary_function<float, float>{
    float exponent;
    CompareGOp(float v):exponent(v) {}
    void setExponent(float v){
        exponent = v;
    }
    
    __host__ __device__
    float operator()(const float& x)  {
        return (exponent<x?1.0:.0);
    }
};

struct CompareGEOp: public thrust::unary_function<float, float>{
    float exponent;
    CompareGEOp(float v):exponent(v) {}
    void setExponent(float v){
        exponent = v;
    }
    
    __host__ __device__
    float operator()(const float& x)  {
        return (exponent<=x?1.0:.0);
    }
};

struct CompareEOp: public thrust::unary_function<float, float>{
    float exponent;
    CompareEOp(float v):exponent(v) {}
    void setExponent(float v){
        exponent = v;
    }
    
    __host__ __device__
    float operator()(const float& x)  {
        return (exponent==x?1.0:.0);
    }
};

struct CompareNEOp: public thrust::unary_function<float, float>{
    float exponent;
    CompareNEOp(float v):exponent(v) {}
    void setExponent(float v){
        exponent = v;
    }
    
    __host__ __device__
    float operator()(const float& x)  {
        return (exponent!=x?1.0:.0);
    }
};

struct CompareLOp: public thrust::unary_function<float, float>{
    float exponent;
    CompareLOp(float v):exponent(v) {}
    void setExponent(float v){
        exponent = v;
    }
    
    __host__ __device__
    float operator()(const float& x)  {
        return (exponent>x?1.0:.0);
    }
};

struct CompareLEOp: public thrust::unary_function<float, float>{
    float exponent;
    CompareLEOp(float v):exponent(v) {}
    void setExponent(float v){
        exponent = v;
    }
    
    __host__ __device__
    float operator()(const float& x)  {
        return (exponent>=x?1.0:.0);
    }
};


struct CompareAGOp{
    __host__ __device__
    float operator()(const float& x,const float& y)  {
        return x>y?1:0;
    }
};

struct CompareAGEOp{
    __host__ __device__
    float operator()(const float& x,const float& y)  {
        return x>=y?1:0;
    }
};

struct CompareAEOp{
    __host__ __device__
    float operator()(const float& x,const float& y)  {
        return x==y?1:0;
    }
};

struct CompareANEOp{
    __host__ __device__
    float operator()(const float& x,const float& y)  {
        return x!=y?1:0;
    }
};

typedef thrust::complex<float> complexf;



void unaryAddmm(float *aMatrixIn1, float *aMatrixIn2, float *aMatrixOut,
              unsigned long aLength,
              Aurora::ValueType aValType1, Aurora::ValueType aValType2)
{
    if (aValType1 == aValType2)
    {
        thrust::plus<float> op;
        thrust::transform(thrust::device,aMatrixIn1,aMatrixIn1+aLength*aValType1,aMatrixIn2,aMatrixOut,op);
    }
    else if(Aurora::Complex == aValType1){
        auto lambda = [=] __device__(const complexf& x, const float& y){
            return complexf(x.real()+y,x.imag());
        };
        thrust::transform(thrust::device,(complexf*)aMatrixIn1,(complexf*)aMatrixIn1+aLength,aMatrixIn2,(complexf*)aMatrixOut,lambda);
    }
    else{
        auto lambda = [=] __device__(const complexf& x, const float& y){
            return complexf(x.real()+y,x.imag());
        };
        thrust::transform(thrust::device,(complexf*)aMatrixIn2,(complexf*)aMatrixIn2+aLength,aMatrixIn1,(complexf*)aMatrixOut,lambda);
    }

}

void unaryAddmv(float *aMatrixIn1, float *aVectorIn2, float *aMatrixOut,
              unsigned long aMatrixLength,unsigned long aVectorLength,
              Aurora::ValueType aValType1, Aurora::ValueType aValType2,
              Aurora::FunctionDirection aVectype)
{
    if (aVectype == Aurora::Column){
        if(aValType1 == aValType2){
            Aurora::LoopVectorIterator<float> rowVectorIter(aVectorIn2,aVectorLength);
            thrust::plus<float> op;
            thrust::transform(thrust::device, aMatrixIn1,aMatrixIn1+aMatrixLength*aValType1,rowVectorIter,aMatrixOut,op);
        }
        else if (aValType1 == Aurora::Complex){
            Aurora::LoopVectorIterator<float> rowVectorIter(aVectorIn2,aVectorLength);
            auto lambda = [=] __device__(const complexf& x, const float& y){
                return complexf(x.real()+y,x.imag());
            };
            thrust::transform(thrust::device, (complexf*)aMatrixIn1,(complexf*)aMatrixIn1+aMatrixLength,rowVectorIter,(complexf*)aMatrixOut,lambda);
        }
        else{
            Aurora::LoopVectorIterator<complexf> rowVectorIter((complexf*)aVectorIn2,aVectorLength);
            auto lambda = [=] __device__(const float& x, const complexf& y){
                return complexf(y.real()+x,y.imag());
            };
            thrust::transform(thrust::device, aMatrixIn1,aMatrixIn1+aMatrixLength,rowVectorIter,(complexf*)aMatrixOut,lambda);
        }
    }
    else{
        int colElementCount = aMatrixLength/aVectorLength;
        if(aValType1 == aValType2){
            Aurora::RowWiseIterator<float> rowIter_Begin(aMatrixIn1,aVectorLength,colElementCount,0);
            Aurora::RowWiseIterator<float> rowIter_End(aMatrixIn1,aVectorLength,colElementCount,aMatrixLength);
            Aurora::LoopVectorIterator<float> rowVectorIter(aVectorIn2,aVectorLength);
            thrust::plus<float> op;
            thrust::transform(thrust::device, rowIter_Begin,rowIter_End,rowVectorIter,aMatrixOut,op);
        }
        else if (aValType1 == Aurora::Complex){
            Aurora::RowWiseIterator<complexf> rowIter_Begin((complexf*)aMatrixIn1,aVectorLength,colElementCount,0);
            Aurora::RowWiseIterator<complexf> rowIter_End((complexf*)aMatrixIn1,aVectorLength,colElementCount,aMatrixLength);
            Aurora::LoopVectorIterator<float> rowVectorIter(aVectorIn2,aVectorLength);
            auto lambda = [=] __device__(const complexf& x, const float& y){
                return complexf(x.real()+y,x.imag());
            };
            thrust::transform(thrust::device, rowIter_Begin,rowIter_End,rowVectorIter,(complexf*)aMatrixOut,lambda);
        }
        else{
            Aurora::RowWiseIterator<float> rowIter_Begin(aMatrixIn1,aVectorLength,colElementCount,0);
            Aurora::RowWiseIterator<float> rowIter_End(aMatrixIn1,aVectorLength,colElementCount,aMatrixLength);
            Aurora::LoopVectorIterator<complexf> rowVectorIter((complexf*)aVectorIn2,aVectorLength);
            auto lambda = [=] __device__(const float& x, const complexf& y){
                return complexf(y.real()+x,y.imag());
            };
            thrust::transform(thrust::device, rowIter_Begin,rowIter_End,rowVectorIter,(complexf*)aMatrixOut,lambda);
        }
    }
}

void unaryAdd(float* aMatrixIn, const float& aVectorIn, float* aMatrixOut, unsigned long  aLength)
{
    thrust::transform(thrust::device,aMatrixIn,aMatrixIn+aLength,aMatrixOut,aVectorIn + _1);
}

void unaryAddc(std::complex<float>* aMatrixIn, const std::complex<float>& aScalarIn, 
                std::complex<float>* aMatrixOut, unsigned long  aLength)
{
    complexf value (aScalarIn.real(), aScalarIn.imag());
    thrust::transform(thrust::device,(complexf*)aMatrixIn,
                    (complexf*)aMatrixIn + aLength,
                    (complexf*)aMatrixOut, value + _1);
}

void unaryMul(float* aMatrixIn, const float& aScalarIn, float* aMatrixOut, unsigned long  aLength)
{
    thrust::transform(thrust::device,aMatrixIn,aMatrixIn+aLength,aMatrixOut,aScalarIn * _1);
}

void unaryMulc(std::complex<float> *aMatrixIn,
               const std::complex<float> &aScalarIn,
               std::complex<float> *aMatrixOut, unsigned long aLength) 
{
    complexf value (aScalarIn.real(), aScalarIn.imag());
    thrust::transform(thrust::device, (complexf *)aMatrixIn,
                      (complexf *)aMatrixIn + aLength, (complexf *)aMatrixOut,
                      value * _1);
}

void unaryMulmm(float *aMatrixIn1, float *aMatrixIn2, float *aMatrixOut,
              unsigned long aLength,
              Aurora::ValueType aValType1, Aurora::ValueType aValType2)
{
    if (aValType1 == aValType2 )
    {
        if(Aurora::Normal == aValType1){
            thrust::multiplies<float> op;
            thrust::transform(thrust::device,aMatrixIn1,aMatrixIn1+aLength*aValType1,aMatrixIn2,aMatrixOut,op);
        }
        else{
            thrust::multiplies<complexf> op;
            thrust::transform(thrust::device, (complexf *)aMatrixIn1,
                              (complexf *)aMatrixIn1 + aLength,
                              (complexf *)aMatrixIn2, (complexf *)aMatrixOut,
                              op);
        }
    }
    else if(Aurora::Complex == aValType1){
        auto lambda = [=] __device__(const complexf& x, const float& y){
            return complexf(x.real()*y,x.imag()*y);
        };
        thrust::transform(thrust::device,(complexf*)aMatrixIn1,(complexf*)aMatrixIn1+aLength,aMatrixIn2,(complexf*)aMatrixOut,lambda);
    }
    else{
        auto lambda = [=] __device__(const complexf& x, const float& y){
            return complexf(x.real()*y,x.imag()*y);
        };
        thrust::transform(thrust::device,(complexf*)aMatrixIn2,(complexf*)aMatrixIn2+aLength,aMatrixIn1,(complexf*)aMatrixOut,lambda);
    }

}

void unaryMulmv(float *aMatrixIn1, float *aVectorIn2, float *aMatrixOut,
              unsigned long aMatrixLength,unsigned long aVectorLength,
              Aurora::ValueType aValType1, Aurora::ValueType aValType2,
              Aurora::FunctionDirection aVectype)
{
    if (aVectype == Aurora::Column){
        if(aValType1 == aValType2){
            if(aValType1 == Aurora::Normal){
                Aurora::LoopVectorIterator<float> rowVectorIter(aVectorIn2,aVectorLength);
                thrust::multiplies<float> op;
                thrust::transform(thrust::device, aMatrixIn1,aMatrixIn1+aMatrixLength*aValType1,rowVectorIter,aMatrixOut,op);
            }
            else{
                Aurora::LoopVectorIterator<complexf> rowVectorIter((complexf*)aVectorIn2,aVectorLength);
                thrust::multiplies<complexf> op;
                thrust::transform(thrust::device, (complexf*)aMatrixIn1,
                            (complexf*)aMatrixIn1+aMatrixLength,rowVectorIter,
                            (complexf*)aMatrixOut,op);
            }
        }
        else if (aValType1 == Aurora::Complex){
            Aurora::LoopVectorIterator<float> rowVectorIter(aVectorIn2,aVectorLength);
            auto lambda = [=] __device__(const complexf& x, const float& y){
                return complexf(x.real()*y,x.imag()*y);
            };
            thrust::transform(thrust::device, (complexf*)aMatrixIn1,(complexf*)aMatrixIn1+aMatrixLength,rowVectorIter,(complexf*)aMatrixOut,lambda);
        }
        else{
            Aurora::LoopVectorIterator<complexf> rowVectorIter((complexf*)aVectorIn2,aVectorLength);
            auto lambda = [=] __device__(const float& x, const complexf& y){
                return complexf(y.real()*x,y.imag()*x);
            };
            thrust::transform(thrust::device, aMatrixIn1,aMatrixIn1+aMatrixLength,rowVectorIter,(complexf*)aMatrixOut,lambda);
        }
    }
    else{
        int colElementCount = aMatrixLength/aVectorLength;
        if(aValType1 == aValType2){
            if(aValType1 == Aurora::Normal){
                Aurora::RowWiseIterator<float> rowIter_Begin(aMatrixIn1,aVectorLength,colElementCount,0);
                Aurora::RowWiseIterator<float> rowIter_End(aMatrixIn1,aVectorLength,colElementCount,aMatrixLength);
                Aurora::LoopVectorIterator<float> rowVectorIter(aVectorIn2,aVectorLength);
                thrust::multiplies<float> op;
                thrust::transform(thrust::device, rowIter_Begin,rowIter_End,rowVectorIter,aMatrixOut,op);
            }
            else{
                Aurora::RowWiseIterator<complexf> rowIter_Begin((complexf*)aMatrixIn1,aVectorLength,colElementCount,0);
                Aurora::RowWiseIterator<complexf> rowIter_End((complexf*)aMatrixIn1,aVectorLength,colElementCount,aMatrixLength);
                Aurora::LoopVectorIterator<complexf> rowVectorIter((complexf*)aVectorIn2,aVectorLength);
                thrust::multiplies<complexf> op;
                thrust::transform(thrust::device, rowIter_Begin,rowIter_End,rowVectorIter,(complexf*)aMatrixOut,op);
            }
        }
        else if (aValType1 == Aurora::Complex){
            Aurora::RowWiseIterator<complexf> rowIter_Begin((complexf*)aMatrixIn1,aVectorLength,colElementCount,0);
            Aurora::RowWiseIterator<complexf> rowIter_End((complexf*)aMatrixIn1,aVectorLength,colElementCount,aMatrixLength);
            Aurora::LoopVectorIterator<float> rowVectorIter(aVectorIn2,aVectorLength);
            auto lambda = [=] __device__(const complexf& x, const float& y){
                return complexf(x.real()*y,x.imag()*y);
            };
            thrust::transform(thrust::device, rowIter_Begin,rowIter_End,rowVectorIter,(complexf*)aMatrixOut,lambda);
        }
        else{
            Aurora::RowWiseIterator<float> rowIter_Begin(aMatrixIn1,aVectorLength,colElementCount,0);
            Aurora::RowWiseIterator<float> rowIter_End(aMatrixIn1,aVectorLength,colElementCount,aMatrixLength);
            Aurora::LoopVectorIterator<complexf> rowVectorIter((complexf*)aVectorIn2,aVectorLength);
            auto lambda = [=] __device__(const float& x, const complexf& y){
                return complexf(y.real()*x,y.imag()*x);
            };
            thrust::transform(thrust::device, rowIter_Begin,rowIter_End,rowVectorIter,(complexf*)aMatrixOut,lambda);
        }
    }
}

void unaryNeg(float* in1, float* out, unsigned long length){
    thrust::negate<float> op;
    thrust::transform(thrust::device,in1,in1+length,out,op);
}

void unarySub(float* in1, const float& in2, float* out, unsigned long length){
    thrust::transform(thrust::device,in1,in1+length,out,_1-in2);
}

void unarySub(const float& in2, float* in1, float* out, unsigned long length){
    thrust::transform(thrust::device,in1,in1+length,out,in2-_1);
}

void unarySubc(std::complex<float> *aMatrixIn,
               const std::complex<float> &aScalarIn,
               std::complex<float> *aMatrixOut, unsigned long aLength)
{
    complexf value (aScalarIn.real(), aScalarIn.imag());
    thrust::transform(thrust::device, (complexf *)aMatrixIn,
                      (complexf *)aMatrixIn + aLength, (complexf *)aMatrixOut,
                      _1 - value);
}

void unarySubc(const std::complex<float> &aScalarIn,
               std::complex<float> *aMatrixIn,
               std::complex<float> *aMatrixOut, unsigned long aLength)
{
    complexf value (aScalarIn.real(), aScalarIn.imag());
    thrust::transform(thrust::device, (complexf *)aMatrixIn,
                      (complexf *)aMatrixIn + aLength, (complexf *)aMatrixOut,
                      value - _1);
}

void unarySubmm(float *aMatrixIn1, float *aMatrixIn2, float *aMatrixOut,
                unsigned long aLength,
                Aurora::ValueType aValType1,
                Aurora::ValueType aValType2 )
{
    if (aValType1 == aValType2 )
    {
        if(Aurora::Normal == aValType1){
            thrust::minus<float> op;
            thrust::transform(thrust::device,aMatrixIn1,aMatrixIn1+aLength*aValType1,aMatrixIn2,aMatrixOut,op);
        }
        else{
            thrust::minus<complexf> op;
            thrust::transform(thrust::device, (complexf *)aMatrixIn1,
                              (complexf *)aMatrixIn1 + aLength,
                              (complexf *)aMatrixIn2, (complexf *)aMatrixOut,
                              op);
        }
    }
    else if(Aurora::Complex == aValType1){
        auto lambda = [=] __device__(const complexf& x, const float& y){
            return complexf(x.real()-y,x.imag());
        };
        thrust::transform(thrust::device,(complexf*)aMatrixIn1,(complexf*)aMatrixIn1+aLength,aMatrixIn2,(complexf*)aMatrixOut,lambda);
    }
    else{
        auto lambda = [=] __device__(const float& x, const complexf& y){
            return complexf(x-y.real(),0-y.imag());
        };
        thrust::transform(thrust::device,aMatrixIn1,aMatrixIn1+aLength,(complexf*)aMatrixIn2,(complexf*)aMatrixOut,lambda);
    }
}

void unarySubmv(float *aMatrixIn1, float *aVectorIn2, float *aMatrixOut,
              unsigned long aMatrixLength,unsigned long aVectorLength,
              Aurora::ValueType aValType1, Aurora::ValueType aValType2, 
              Aurora::FunctionDirection aVectype,int direction)
{
    if (aVectype == Aurora::Column){
        //类型一样时，逐元素处理即可
        if(aValType1 == aValType2){
            Aurora::LoopVectorIterator<float> rowVectorIter(aVectorIn2,aVectorLength);
            auto lambda = [=] __device__(const float& x, const float& y){
                return direction==0?x-y:y-x;
            };
            thrust::transform(thrust::device, aMatrixIn1,aMatrixIn1+aMatrixLength*aValType1,rowVectorIter,aMatrixOut,lambda);
        }
        else if (aValType1 == Aurora::Complex){
            Aurora::LoopVectorIterator<float> rowVectorIter(aVectorIn2,aVectorLength);
            auto lambda = [=] __device__(const complexf& x, const float& y){
                return  direction==0?complexf(x.real()-y,x.imag()):complexf(y-x.real(),-x.imag());
            };
            thrust::transform(thrust::device, (complexf*)aMatrixIn1,(complexf*)aMatrixIn1+aMatrixLength,rowVectorIter,(complexf*)aMatrixOut,lambda);
        }
        else{
            Aurora::LoopVectorIterator<complexf> rowVectorIter((complexf*)aVectorIn2,aVectorLength);
            auto lambda = [=] __device__(const float& x, const complexf& y){
                return  direction==0?complexf(x-y.real(),-y.imag()):complexf(y.real()-x,y.imag());
            };
            thrust::transform(thrust::device, aMatrixIn1,aMatrixIn1+aMatrixLength,rowVectorIter,(complexf*)aMatrixOut,lambda);
        }
    }
    else{
        int colElementCount = aMatrixLength/aVectorLength;
        if(aValType1 == aValType2){
            Aurora::RowWiseIterator<float> rowIter_Begin(aMatrixIn1,aVectorLength,colElementCount,0);
            Aurora::RowWiseIterator<float> rowIter_End(aMatrixIn1,aVectorLength,colElementCount,aMatrixLength);
            Aurora::LoopVectorIterator<float> rowVectorIter(aVectorIn2,aVectorLength);
            Aurora::RowWiseIterator<float> outIter(aMatrixOut,aVectorLength,colElementCount,0);
            auto lambda = [=] __device__(const float& x, const float& y){
                return direction==0?x-y:y-x;
            };
            thrust::transform(thrust::device, rowIter_Begin,rowIter_End,rowVectorIter,outIter,lambda);
        }
        else if (aValType1 == Aurora::Complex){
            Aurora::RowWiseIterator<complexf> rowIter_Begin((complexf*)aMatrixIn1,aVectorLength,colElementCount,0);
            Aurora::RowWiseIterator<complexf> rowIter_End((complexf*)aMatrixIn1,aVectorLength,colElementCount,aMatrixLength);
            Aurora::LoopVectorIterator<float> rowVectorIter(aVectorIn2,aVectorLength);
            Aurora::RowWiseIterator<complexf> outIter((complexf*)aMatrixOut,aVectorLength,colElementCount,0);
            auto lambda = [=] __device__(const complexf& x, const float& y){
                return  direction==0?complexf(x.real()-y,x.imag()):complexf(y-x.real(),-x.imag());
            };
            thrust::transform(thrust::device, rowIter_Begin,rowIter_End,rowVectorIter,outIter,lambda);
        }
        else{
            Aurora::RowWiseIterator<float> rowIter_Begin(aMatrixIn1,aVectorLength,colElementCount,0);
            Aurora::RowWiseIterator<float> rowIter_End(aMatrixIn1,aVectorLength,colElementCount,aMatrixLength);
            Aurora::LoopVectorIterator<complexf> rowVectorIter((complexf*)aVectorIn2,aVectorLength);
            Aurora::RowWiseIterator<complexf> outIter((complexf*)aMatrixOut,aVectorLength,colElementCount,0);
            auto lambda = [=] __device__(const float& x, const complexf& y){
                return  direction==0?complexf(x-y.real(),-y.imag()):complexf(y.real()-x,y.imag());
            };
            thrust::transform(thrust::device, rowIter_Begin,rowIter_End,rowVectorIter,outIter,lambda);
        }
    }
}

void unaryDiv(float* in1, const float& in2, float* out, unsigned long length){
    thrust::transform(thrust::device,in1,in1+length,out,_1/in2);
}

void unaryDiv(const float& in2, float* in1, float* out, unsigned long length){
    thrust::transform(thrust::device,in1,in1+length,out,in2/_1);
}

void unaryDivc(std::complex<float> *aMatrixIn,
               const std::complex<float> &aScalarIn,
               std::complex<float> *aMatrixOut, unsigned long aLength)
{
    complexf value (aScalarIn.real(), aScalarIn.imag());
    thrust::transform(thrust::device, (complexf *)aMatrixIn,
                      (complexf *)aMatrixIn + aLength, (complexf *)aMatrixOut,
                      _1 / value);
}

void unaryDivc(const std::complex<float> &aScalarIn,
               std::complex<float> *aMatrixIn,
               std::complex<float> *aMatrixOut, unsigned long aLength)
{
    complexf value (aScalarIn.real(), aScalarIn.imag());
    thrust::transform(thrust::device, (complexf *)aMatrixIn,
                      (complexf *)aMatrixIn + aLength, (complexf *)aMatrixOut,
                      value / _1);
}

void unaryDivmm(float *aMatrixIn1, float *aMatrixIn2, float *aMatrixOut,
                unsigned long aLength,
                Aurora::ValueType aValType1,
                Aurora::ValueType aValType2 )
{
    if (aValType1 == aValType2 )
    {
        if(Aurora::Normal == aValType1){
            thrust::divides<float> op;
            thrust::transform(thrust::device,aMatrixIn1,aMatrixIn1+aLength*aValType1,aMatrixIn2,aMatrixOut,op);
        }
        else{
            thrust::divides<complexf> op;
            thrust::transform(thrust::device, (complexf *)aMatrixIn1,
                              (complexf *)aMatrixIn1 + aLength,
                              (complexf *)aMatrixIn2, (complexf *)aMatrixOut,
                              op);
        }
    }
    else if(Aurora::Complex == aValType1){
        auto lambda = [=] __device__(const complexf& x, const float& y){
            return x/complexf(y,0);
        };
        thrust::transform(thrust::device,(complexf*)aMatrixIn1,(complexf*)aMatrixIn1+aLength,aMatrixIn2,(complexf*)aMatrixOut,lambda);
    }
    else{
        auto lambda = [=] __device__(const float& x, const complexf& y){
            return complexf(x,0)/y;
        };
        thrust::transform(thrust::device,aMatrixIn1,aMatrixIn1+aLength,(complexf*)aMatrixIn2,(complexf*)aMatrixOut,lambda);
    }
}

void unaryDivmv(float *aMatrixIn1, float *aVectorIn2, float *aMatrixOut,
              unsigned long aMatrixLength,unsigned long aVectorLength,
              Aurora::ValueType aValType1, Aurora::ValueType aValType2, 
              Aurora::FunctionDirection aVectype,int direction)
{
    if (aVectype == Aurora::Column){
        //类型一样时，逐元素处理即可
        if(aValType1 == aValType2){
            if (aValType1==Aurora::Normal){
                Aurora::LoopVectorIterator<float> rowVectorIter(aVectorIn2,aVectorLength);
                auto lambda = [=] __device__(const float& x, const float& y){
                    return direction==0?x/y:y/x;
                };
                thrust::transform(thrust::device, aMatrixIn1,aMatrixIn1+aMatrixLength,rowVectorIter,aMatrixOut,lambda);
            }
            else{
                Aurora::LoopVectorIterator<complexf> rowVectorIter((complexf*)aVectorIn2,aVectorLength);
                auto lambda = [=] __device__(const complexf& x, const complexf& y){
                    return direction==0?x/y:y/x;
                };
                thrust::transform(thrust::device, (complexf*)aMatrixIn1,
                    (complexf*)aMatrixIn1+aMatrixLength,rowVectorIter,(complexf*)aMatrixOut,lambda);
            }

        }
        else if (aValType1 == Aurora::Complex){
            Aurora::LoopVectorIterator<float> rowVectorIter(aVectorIn2,aVectorLength);
            auto lambda = [=] __device__(const complexf& x, const float& y){
                complexf v (y,0);
                return  direction==0?x/v:v/x;
            };
            thrust::transform(thrust::device, (complexf*)aMatrixIn1,(complexf*)aMatrixIn1+aMatrixLength,rowVectorIter,(complexf*)aMatrixOut,lambda);
        }
        else{
            Aurora::LoopVectorIterator<complexf> rowVectorIter((complexf*)aVectorIn2,aVectorLength);
            auto lambda = [=] __device__(const float& x, const complexf& y){
                complexf v (x,0);
                return  direction==0?v/y:y/v;
            };
            thrust::transform(thrust::device, aMatrixIn1,aMatrixIn1+aMatrixLength,rowVectorIter,(complexf*)aMatrixOut,lambda);
        }
    }
    else{
        int colElementCount = aMatrixLength/aVectorLength;
        if(aValType1 == aValType2){
            if (aValType1 == Aurora::Normal)
            {
                Aurora::RowWiseIterator<float> rowIter_Begin(aMatrixIn1,aVectorLength,colElementCount,0);
                Aurora::RowWiseIterator<float> rowIter_End(aMatrixIn1,aVectorLength,colElementCount,aMatrixLength);
                Aurora::LoopVectorIterator<float> rowVectorIter(aVectorIn2,aVectorLength);
                Aurora::RowWiseIterator<float> outIter(aMatrixOut,aVectorLength,colElementCount,0);
                auto lambda = [=] __device__(const float& x, const float& y){
                    return direction==0?x/y:y/x;
                };
                thrust::transform(thrust::device, rowIter_Begin,rowIter_End,rowVectorIter,outIter,lambda);
            }
            else{
                Aurora::RowWiseIterator<complexf> rowIter_Begin((complexf*)aMatrixIn1,aVectorLength,colElementCount,0);
                Aurora::RowWiseIterator<complexf> rowIter_End((complexf*)aMatrixIn1,aVectorLength,colElementCount,aMatrixLength);
                Aurora::LoopVectorIterator<complexf> rowVectorIter((complexf*)aVectorIn2,aVectorLength);
                Aurora::RowWiseIterator<complexf> outIter((complexf*)aMatrixOut,aVectorLength,colElementCount,0);
                auto lambda = [=] __device__(const complexf& x, const complexf& y){
                    return direction==0?x/y:y/x;
                };
                thrust::transform(thrust::device, rowIter_Begin,rowIter_End,rowVectorIter,outIter,lambda); 
            }

        }
        else if (aValType1 == Aurora::Complex){
            Aurora::RowWiseIterator<complexf> rowIter_Begin((complexf*)aMatrixIn1,aVectorLength,colElementCount,0);
            Aurora::RowWiseIterator<complexf> rowIter_End((complexf*)aMatrixIn1,aVectorLength,colElementCount,aMatrixLength);
            Aurora::LoopVectorIterator<float> rowVectorIter(aVectorIn2,aVectorLength);
            Aurora::RowWiseIterator<complexf> outIter((complexf*)aMatrixOut,aVectorLength,colElementCount,0);
            auto lambda = [=] __device__(const complexf& x, const float& y){
                complexf v (y,0);
                return  direction==0?x/v:v/x;
            };
            thrust::transform(thrust::device, rowIter_Begin,rowIter_End,rowVectorIter,outIter,lambda);
        }
        else{
            Aurora::RowWiseIterator<float> rowIter_Begin(aMatrixIn1,aVectorLength,colElementCount,0);
            Aurora::RowWiseIterator<float> rowIter_End(aMatrixIn1,aVectorLength,colElementCount,aMatrixLength);
            Aurora::LoopVectorIterator<complexf> rowVectorIter((complexf*)aVectorIn2,aVectorLength);
            Aurora::RowWiseIterator<complexf> outIter((complexf*)aMatrixOut,aVectorLength,colElementCount,0);
            auto lambda = [=] __device__(const float& x, const complexf& y){
                complexf v (x,0);
                return  direction==0?v/y:y/v;
            };
            thrust::transform(thrust::device, rowIter_Begin,rowIter_End,rowVectorIter,outIter,lambda);
        }
    }
}



void unaryPow(float* in1, float N,float* out, unsigned long length){
    if (N == 0.0f)
    {
        thrust::fill(thrust::device,out,out+length,1);
        return;
    }
    if (N == 1.0f)
    {
        thrust::copy(thrust::device,in1,in1+length,out);
        return;
    }
    if (N == 2.0f){
        thrust::square<float> op;
        thrust::transform(thrust::device,in1,in1+length,out,op);
        return;
    }
    thrust::transform(thrust::device,in1,in1+length,out,PowOp(N));
}

void unaryCompare(float* in1, const float& in2, float* out, unsigned long length, int type){
    switch (type)
    {
        case G:
            thrust::transform(thrust::device,in1,in1+length,out,CompareGOp(in2));
            break;
        case GE:
            thrust::transform(thrust::device,in1,in1+length,out,CompareGEOp(in2));
            break;
        case E:
            thrust::transform(thrust::device,in1,in1+length,out,CompareEOp(in2));
            break;
        case NE:
            thrust::transform(thrust::device,in1,in1+length,out,CompareNEOp(in2));
            break;
        case LE:
            thrust::transform(thrust::device,in1,in1+length,out,CompareLEOp(in2));
            break;
        case L:
            thrust::transform(thrust::device,in1,in1+length,out,CompareLOp(in2));
            break;
        default:
            break;
    }
}
void unaryCompare(const float& in1, float* in2, float* out, unsigned long length, int type){
    switch (type)
    {
        case G:
            thrust::transform(thrust::device,in2,in2+length,out,CompareLOp(in1));
            break;
        case GE:
            thrust::transform(thrust::device,in2,in2+length,out,CompareLEOp(in1));
            break;
        case E:
            thrust::transform(thrust::device,in2,in2+length,out,CompareEOp(in1));
            break;
        case NE:
            thrust::transform(thrust::device,in2,in2+length,out,CompareNEOp(in1));
            break;
        case LE:
            thrust::transform(thrust::device,in2,in2+length,out,CompareGEOp(in1));
            break;
        case L:
            thrust::transform(thrust::device,in2,in2+length,out,CompareGOp(in1));
            break;
        default:
            break;
    }
}
void unaryCompare(float* in1, float* in2, float* out, unsigned long length, int type){
    switch (type)
    {
        case G:
            thrust::transform(thrust::device,in1,in1+length,in2,out,CompareAGOp());
            break;
        case GE:
            thrust::transform(thrust::device,in1,in1+length,in2,out,CompareAGEOp());
            break;
        case E:
            thrust::transform(thrust::device,in1,in1+length,in2,out,CompareAEOp());
            break;
        case NE:
            thrust::transform(thrust::device,in1,in1+length,in2,out,CompareANEOp());
            break;
        case LE:
            thrust::transform(thrust::device,in2,in2+length,in1,out,CompareAGEOp());
            break;
        case L:
            thrust::transform(thrust::device,in2,in2+length,in1,out,CompareAGOp());
            break;
        default:
            break;
    }
}

void thrustFill(float* aBegin, float* aEnd, float aValue)
{
    thrust::fill(thrust::device, aBegin, aEnd, aValue);
}

void thrustFill(float* aBegin, float* aEnd, std::complex<float> aValue)
{
    thrust::fill(thrust::device, (std::complex<float>*)aBegin, (std::complex<float>*)aEnd, aValue);
}


