void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    size_t numRow, numCol,numPoints, foundIdx;
    double *arr;
    mxArray *retIdx;
    
    if(nrhs<1){
        mexErrMsgTxt("Not enough inputs.");
        return;
    }
    
    if(nrhs>1) {
        mexErrMsgTxt("Too many inputs.");
        return;
    }
    
    if(nlhs>1) {
        mexErrMsgTxt("Too many outputs.");
    }
    
    /*Verify the validity of the vector to search.*/
    checkRealDoubleArray(prhs[0]);
    numRow = mxGetM(prhs[0]);
    numCol = mxGetN(prhs[0]);
    if(numRow>1&&numCol>1){
        mexErrMsgTxt("Too many dimensions in the array provided.");
        return;
    } else {
        if(numRow>numCol) {
            numPoints=numRow;
        } else {
            numPoints=numCol;
        }
    }
    
    arr = reinterpret_cast<double*>(mxGetData(prhs[0]));
    foundIdx= findFirstMaxCPP(arr,numPoints);
    
    //Set the return value
    retIdx=allocUnsignedSizeMatInMatlab(1,1);
    *reinterpret_cast<size_t *>(mxGetData(retIdx))=foundIdx+1;
    plhs[0]=retIdx;
}
void mexFunction(const int nlhs, mxArray *plhs[], const int nrhs, const mxArray *prhs[]) {
    double u, scalFactor;
    ClusterSetCPP<double> HBar;
    ClusterSetCPP<double> dHBardu;//The first derivatives
    ClusterSetCPP<double> d2HBardu2;//The second derivatives
    size_t M, numH, i;
    mxArray *CSRetVal;
    mxArray *clusterElsMATLAB,*clusterSizesMATLAB, *offsetArrayMATLAB;
    
    if(nrhs!=3){
        mexErrMsgTxt("Incorrect number of inputs.");
        return;
    }

    u=getDoubleFromMatlab(prhs[0]);
    M=getSizeTFromMatlab(prhs[1]);
    scalFactor=getDoubleFromMatlab(prhs[2]);
    
    if(M<3) {
       mexErrMsgTxt("The maximum order should be at least 3.");
       return; 
    }
    
    numH=(M+1)*(M+2)/2;
    
    //Allocate space for the results.
    clusterElsMATLAB=mxCreateDoubleMatrix(numH,1,mxREAL);
    clusterSizesMATLAB=allocUnsignedSizeMatInMatlab(M+1,1);
    offsetArrayMATLAB=allocUnsignedSizeMatInMatlab(M+1,1);
    
    HBar.numClust=M+1;
    HBar.totalNumEl=numH;
    HBar.clusterEls=reinterpret_cast<double*>(mxGetData(clusterElsMATLAB));
    HBar.offsetArray=reinterpret_cast<size_t*>(mxGetData(offsetArrayMATLAB));
    HBar.clusterSizes=reinterpret_cast<size_t*>(mxGetData(clusterSizesMATLAB));
    
    //Initialize the offset array and cluster sizes.
    HBar.offsetArray[0]=0;
    HBar.clusterSizes[0]=1;
    for(i=1;i<=M;i++){
        HBar.clusterSizes[i]=i+1;
        HBar.offsetArray[i]=HBar.offsetArray[i-1]+HBar.clusterSizes[i-1];
    }
    
    normHelmHoltzCPP(HBar,u,scalFactor);
    
    //Set the first return value
    mexCallMATLAB(1,&CSRetVal,0, 0, "ClusterSet");
    mxSetProperty(CSRetVal,0,"clusterEls",clusterElsMATLAB);
    mxSetProperty(CSRetVal,0,"clusterSizes",clusterSizesMATLAB);
    mxSetProperty(CSRetVal,0,"offsetArray",offsetArrayMATLAB);
    
    plhs[0]=CSRetVal;
    
    if(nlhs>1) {//Compute the first derivatives, if they are desired.
        mxArray *clusterEls1stDerivMATLAB=mxCreateDoubleMatrix(numH,1,mxREAL);
        
        dHBardu.numClust=M+1;
        dHBardu.totalNumEl=numH;
        dHBardu.clusterEls=reinterpret_cast<double*>(mxGetData(clusterEls1stDerivMATLAB));
        dHBardu.offsetArray=reinterpret_cast<size_t*>(mxGetData(offsetArrayMATLAB));
        dHBardu.clusterSizes=reinterpret_cast<size_t*>(mxGetData(clusterSizesMATLAB));
        
        normHelmHoltzDerivCPP(dHBardu,HBar);
        //Set the second return value
        mexCallMATLAB(1,&CSRetVal,0, 0, "ClusterSet");
        mxSetProperty(CSRetVal,0,"clusterEls",clusterEls1stDerivMATLAB);
        mxSetProperty(CSRetVal,0,"clusterSizes",clusterSizesMATLAB);
        mxSetProperty(CSRetVal,0,"offsetArray",offsetArrayMATLAB);

        plhs[1]=CSRetVal;
        mxDestroyArray(clusterEls1stDerivMATLAB);
    }
    
    if(nlhs>2) {//Compute the second derivatives if they are desired.
        mxArray *clusterEls2ndDerivMATLAB=mxCreateDoubleMatrix(numH,1,mxREAL);
        
        d2HBardu2.numClust=M+1;
        d2HBardu2.totalNumEl=numH;
        d2HBardu2.clusterEls=reinterpret_cast<double*>(mxGetData(clusterEls2ndDerivMATLAB));
        d2HBardu2.offsetArray=reinterpret_cast<size_t*>(mxGetData(offsetArrayMATLAB));
        d2HBardu2.clusterSizes=reinterpret_cast<size_t*>(mxGetData(clusterSizesMATLAB));
        
        normHelmHoltzDeriv2CPP(d2HBardu2,HBar);
        
        //Set the third return value
        mexCallMATLAB(1,&CSRetVal,0, 0, "ClusterSet");
        mxSetProperty(CSRetVal,0,"clusterEls",clusterEls2ndDerivMATLAB);
        mxSetProperty(CSRetVal,0,"clusterSizes",clusterSizesMATLAB);
        mxSetProperty(CSRetVal,0,"offsetArray",offsetArrayMATLAB);

        plhs[2]=CSRetVal;
        mxDestroyArray(clusterEls2ndDerivMATLAB);
    }
    
    //Free the buffers. The mxSetProperty command copied the data.
    mxDestroyArray(clusterElsMATLAB);
    mxDestroyArray(clusterSizesMATLAB);
    mxDestroyArray(offsetArrayMATLAB);
}
void mexFunction(const int nlhs, mxArray *plhs[], const int nrhs, const mxArray *prhs[]) {
    size_t n,j;
    size_t nCard;
    bool isLast, lastPassed;
    mxArray *codeArray;
    
    if(nrhs<1){
        mexErrMsgTxt("Not enough inputs.");
    }
    
    if(nrhs>2){
        mexErrMsgTxt("Too many inputs.");
    }
    
    if(nlhs>4) {
        mexErrMsgTxt("Too many outputs.");
    }
    
    //If an empty code matrix is passed, then the second argument is
    //required, and we will return the first gray code in the sequence.
    if(mxIsEmpty(prhs[0])) {
        mwSize dims[2];
        if(nrhs<2) {
            mexErrMsgTxt("The second argument is required when an empty code matrix is passed.");
        }
        
        dims[0]=getSizeTFromMatlab(prhs[1]);
        dims[1]=1;
        //Allocate the array; this also initializes all of the elements to
        //0.
        codeArray=mxCreateLogicalArray(2, dims);
        
        //This is the code
        plhs[0]=codeArray;
        
        if(nlhs>1) {
            //This is nCard
            plhs[1]=mxCreateDoubleScalar(0.0);
            
            if(nlhs>2) {
                //This is isLast
                plhs[2]=mxCreateLogicalScalar(false);
                
                if(nlhs>3) {
                    //This is j.
                    plhs[3]=mxCreateDoubleMatrix(0, 0, mxREAL);
                }
            }
        }
        return;
    }
    
    //The code array cannot be complex.
    if(mxIsComplex(prhs[0])!=false) {
        mexErrMsgTxt("The code array cannot be complex.");
    }
    
    //Copy the code value so that the input matrix is not modified on
    //return.
    {
        size_t n1,n2;
        n1=mxGetM(prhs[0]);
        n2=mxGetN(prhs[0]);

        if((n1==1&&n2>=1)||(n2==1&&n1>=1)) {
            n=std::max(n1,n2);
            
            codeArray=mxDuplicateArray(prhs[0]);
        } else {
            mexErrMsgTxt("The code vector has the wrong dimensionality.");
        }
    }

    if(nrhs>1) {
        nCard=getSizeTFromMatlab(prhs[1]);
    } else {
        mxArray *lhs[1];
        //Sum up the ones in codeArray to get nCard if it is not provided.
        mexCallMATLAB(1,lhs,1, &codeArray, "sum");
        nCard=getSizeTFromMatlab(lhs[0]);
        mxDestroyArray(lhs[0]);
    }
    
    //The type of the data in the code array is whatever the user passed to
    //the function. The function has to be called with the correct template 
    //value for the type of the code.
    lastPassed=false;
    switch(mxGetClassID(codeArray)){
        case mxCHAR_CLASS:
        {
            mxChar *code=(mxChar*)mxGetData(codeArray);
            
            if(nCard==(size_t)code[n-1]&&nCard!=0) {
                lastPassed=true;
            } else{
                isLast=getNextGrayCodeCPP(n, code, nCard, j);
            }
            break;
        }
        case mxLOGICAL_CLASS:
        {
            mxLogical* code=(mxLogical*)mxGetData(codeArray); 
            
            if(nCard==(size_t)code[n-1]&&nCard!=0) {
                lastPassed=true;
            } else{
                isLast=getNextGrayCodeCPP(n, code, nCard, j);
            }
            break;
        }
        case mxDOUBLE_CLASS:
        {
            double* code=(double*)mxGetData(codeArray);
            
            if(nCard==(size_t)code[n-1]&&nCard!=0) {
                lastPassed=true;
            } else{
                isLast=getNextGrayCodeCPP(n, code, nCard, j);
            }
            break;
        }
        case mxSINGLE_CLASS:
        {
            float* code=(float*)mxGetData(codeArray);
            
            if(nCard==(size_t)code[n-1]&&nCard!=0) {
                lastPassed=true;
            } else{
                isLast=getNextGrayCodeCPP(n, code, nCard, j);
            }
            break;
        }
        case mxINT8_CLASS:
        {
            int8_T* code=(int8_T*)mxGetData(codeArray);
            
            if(nCard==(size_t)code[n-1]&&nCard!=0) {
                lastPassed=true;
            } else{
                isLast=getNextGrayCodeCPP(n, code, nCard, j);
            }
            break;
        }
        case mxUINT8_CLASS:
        {
            uint8_T* code=(uint8_T*)mxGetData(codeArray);
            
            if(nCard==(size_t)code[n-1]&&nCard!=0) {
                lastPassed=true;
            } else{
                isLast=getNextGrayCodeCPP(n, code, nCard, j);
            }
            break;
        }
        case mxINT16_CLASS:
        {
            int16_T* code=(int16_T*)mxGetData(codeArray);
            
            if(nCard==(size_t)code[n-1]&&nCard!=0) {
                lastPassed=true;
            } else{
                isLast=getNextGrayCodeCPP(n, code, nCard, j);
            }
            break;
        }
        case mxUINT16_CLASS:
        {
            uint16_T* code=(uint16_T*)mxGetData(codeArray);
            
            if(nCard==(size_t)code[n-1]&&nCard!=0) {
                lastPassed=true;
            } else{
                isLast=getNextGrayCodeCPP(n, code, nCard, j);
            }
            break;
        }
        case mxINT32_CLASS:
        {
            int32_T* code=(int32_T*)mxGetData(codeArray);
            
            if(nCard==(size_t)code[n-1]&&nCard!=0) {
                lastPassed=true;
            } else{
                isLast=getNextGrayCodeCPP(n, code, nCard, j);
            }
            break;
        }
        case mxUINT32_CLASS:
        {
            uint32_T* code=(uint32_T*)mxGetData(codeArray);
            
            if(nCard==(size_t)code[n-1]&&nCard!=0) {
                lastPassed=true;
            } else{
                isLast=getNextGrayCodeCPP(n, code, nCard, j);
            }
            break;
        }
        case mxINT64_CLASS:
        {
            int64_T* code=(int64_T*)mxGetData(codeArray);
            
            if(nCard==(size_t)code[n-1]&&nCard!=0) {
                lastPassed=true;
            } else{
                isLast=getNextGrayCodeCPP(n, code, nCard, j);
            }
            break;
        }
        case mxUINT64_CLASS:
        {
            uint64_T* code=(uint64_T*)mxGetData(codeArray);   
            
            if(nCard==(size_t)code[n-1]&&nCard!=0) {
                lastPassed=true;
            } else{
                isLast=getNextGrayCodeCPP(n, code, nCard, j);
            }
            break;
        }
        default:
            mexErrMsgTxt("The code vector is of an unknown data type.");
    }
    
    //If the final gray code was passed, then just return empty matrices
    //and put n in nCard. That way, if called again, the function will
    //start from the beginning.
    if(lastPassed==true) {
        mxDestroyArray(codeArray);
        plhs[0]=mxCreateDoubleMatrix(0, 0, mxREAL);
        if(nlhs>1) {
            mxArray *nCardMat=allocUnsignedSizeMatInMatlab(1, 1);
            *(size_t*)mxGetData(nCardMat)=n;

            plhs[1]=nCardMat;
            if(nlhs>2) {
                //This is isLast
                plhs[2]=mxCreateDoubleMatrix(0, 0, mxREAL);;

                if(nlhs>3) {
                    //This is j
                    plhs[3]=mxCreateDoubleMatrix(0, 0, mxREAL);;
                }
            }
        }
        
        return;   
    }
    
    //Set the return values for the case when the last code was not passed.
    plhs[0]=codeArray;
    if(nlhs>1) {
        mxArray *nCardMat=allocUnsignedSizeMatInMatlab(1, 1);
        *(size_t*)mxGetData(nCardMat)=nCard;
        
        plhs[1]=nCardMat;
        if(nlhs>2) {
            //This is isLast
            plhs[2]=mxCreateLogicalScalar(isLast);

            if(nlhs>3) {
                mxArray *jMat=allocUnsignedSizeMatInMatlab(1, 1);
                //Increment j to be an index for Matlab.
                j++;
                *(size_t*)mxGetData(jMat)=j;
                
                plhs[3]=jMat;
            }
        }
    }
}