static double MatlabCallback(int n, const double *x, int *undefined_flag, void *data) {
    mxArray *rhs[2];
    mxArray *lhs[2];
    double *oldPtr;
    double fVal;
    bool violatesConstraints;

    //feval in Matlab will take the function handle and the state as
    //inputs.
    //The first function handle is f. 
    rhs[0]=(mxArray*)data;
    rhs[1]=mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL);

    //Set the matrix data to x 
    oldPtr=mxGetPr(rhs[1]);
    
    //x will not be modified, but the const must be typecast away to use
    //the mxSetPr function.    
    mxSetPr(rhs[1],(double*)x);
    mxSetM(rhs[1], (size_t)n);
    mxSetN(rhs[1], 1);
    
    //Get the function value and gradient.
    mexCallMATLAB(2,lhs,2,rhs,"feval");
    
    //Get the function value.
    fVal=getDoubleFromMatlab(lhs[0]);
      
    violatesConstraints=getBoolFromMatlab(lhs[1]);
    
    if(violatesConstraints) {
        *undefined_flag=1;
    }
    
    //Get rid of the returned Matlab Matrices.
    mxDestroyArray(lhs[0]);
    mxDestroyArray(lhs[1]);
    
    //Set the data pointer back to what it was during allocation that
    //mxDestroyArray does not have a problem. 
    mxSetPr(rhs[1],oldPtr);
    mxSetM(rhs[1], 0);
    mxSetN(rhs[1], 0);
          
    //Get rid of the temporary natrix.
    mxDestroyArray(rhs[1]);

	return fVal;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double gain, *C, CDelta;
    size_t numRow, numCol, i;
    ptrdiff_t *col4row, *row4col;
    mxArray *col4rowMATLAB, *row4colMATLAB, *uMATLAB, *vMATLAB, *CMat;
    bool didFlip=false;
    bool maximize=false;
    
    if(nrhs<1){
        mexErrMsgTxt("Not enough inputs.");
    }
    
    if(nrhs==2){
        maximize=getBoolFromMatlab(prhs[1]);
    }
    
    if(nrhs>2) {
        mexErrMsgTxt("Too many inputs.");
    }
    
    if(nlhs>5) {
        mexErrMsgTxt("Too many outputs.");
    }
    
    /*Verify the validity of the assignment matrix.*/
    checkRealDoubleArray(prhs[0]);
    
    /* Get the dimensions of the input data and the pointer to the matrix.
     * It is assumed that the matrix is not so large in M or N as to cause
     * an overflow when using a SIGNED integer data type.*/
    numRow = mxGetM(prhs[0]);
    numCol = mxGetN(prhs[0]);
    
    /* Transpose the matrix, if necessary, so that the number of rows is
     * >= the number of columns.*/
    if(numRow>=numCol) {
        CMat=mxDuplicateArray(prhs[0]);
    } else {
        size_t temp;
        
        temp=numCol;
        numCol=numRow;
        numRow=temp;
        
        CMat=mxCreateDoubleMatrix(numCol,numRow,mxREAL);
        mexCallMATLAB(1, &CMat, 1, (mxArray **)&prhs[0], "transpose");
        didFlip=true;
    }
    
    C = (double*)mxGetData(CMat);
    
    /* The cost matrix must have all non-negative elements for the
     * assignment algorithm to work. This forces all of the elements to be
     * positive. The delta is added back in when computing the gain in the
     * end.*/
    if(maximize==false) {
        CDelta=INFINITY;
        for(i=0;i<numRow*numCol;i++) {
            if(C[i]<CDelta)
                CDelta=C[i];
        }

        for(i=0;i<numRow*numCol;i++) {
            C[i]=C[i]-CDelta;
        }
    } else {
        CDelta=-INFINITY;
        for(i=0;i<numRow*numCol;i++) {
            if(C[i]>CDelta)
                CDelta=C[i];
        }

        for(i=0;i<numRow*numCol;i++) {
            C[i]=-C[i]+CDelta;
        }
    }
    
    CDelta=CDelta*numCol;
    
   //Allocate space for the return variables to Matlab.
    
    col4rowMATLAB= allocSignedSizeMatInMatlab(numRow, 1);
    row4colMATLAB= allocSignedSizeMatInMatlab(numCol, 1);
    
    /* These will hold the dual variable values. They are all initialized
     * to zero.*/
    uMATLAB = mxCreateNumericMatrix(numCol,1,mxDOUBLE_CLASS,mxREAL);
    vMATLAB = mxCreateNumericMatrix(numRow,1,mxDOUBLE_CLASS,mxREAL);
    
    col4row=(ptrdiff_t*)mxGetData(col4rowMATLAB);
    row4col=(ptrdiff_t*)mxGetData(row4colMATLAB);
    
    gain=shortestPathCFast(C,col4row,row4col, (double*)mxGetData(uMATLAB), (double*)mxGetData(vMATLAB), numRow, numCol);
    
    mxDestroyArray(CMat);
    /* If a transposed array was used */
    if(didFlip==true) {
        size_t temp;
        ptrdiff_t *tempIPtr;
        mxArray *tempMat;

        temp=numCol;
        numCol=numRow;
        numRow=temp;
        
        tempIPtr=row4col;
        row4col=col4row;
        col4row=tempIPtr;
        
        tempMat=row4colMATLAB;
        row4colMATLAB=col4rowMATLAB;
        col4rowMATLAB=tempMat;
        
        tempMat=uMATLAB;
        uMATLAB=vMATLAB;
        vMATLAB=tempMat;
    }
    
    //If there is no feasible solution.
    if(gain==-1){
        mxDestroyArray(col4rowMATLAB);
        mxDestroyArray(row4colMATLAB);
        
        plhs[0]=mxCreateDoubleMatrix(0,0,mxREAL);
        if(nlhs>1){
            plhs[1]=mxCreateDoubleMatrix(0,0,mxREAL);
            
            if(nlhs>2){
                plhs[2]=mxCreateDoubleScalar(gain);
                
                if(nlhs>3) {
                    plhs[3]=uMATLAB;
                    
                    if(nlhs>4){
                        plhs[4]=vMATLAB;
                    }
                }
                
            }
        }
        return;
    } else {
        
        /* Adjust for shifting that was done to make everything positive.*/
        if(maximize==false) {
            gain=gain+CDelta;

        } else {
            gain=-gain+CDelta;
        }
        
        /* Convert the C indices into indices for MATLAB.*/
        for(i=0;i<numRow;i++){
            col4row[i]=col4row[i]+1;
        }
                
        plhs[0]=col4rowMATLAB;
        if(nlhs>1){
            plhs[1]=row4colMATLAB;
            
            for(i=0;i<numCol;i++){
                row4col[i]=row4col[i]+1;
            }
            
            if(nlhs>2){
                plhs[2]=mxCreateDoubleScalar(gain);
                
                if(nlhs>3) {
                    plhs[3]=uMATLAB;
                    
                    if(nlhs>4){
                        plhs[4]=vMATLAB;
                    }
                }
            }
        }  
    }
    
    /*Free the u and v matrices if they are not returned.*/
    if(nlhs<4){
        mxDestroyArray(uMATLAB);
    }
    if(nlhs<5){
        mxDestroyArray(vMATLAB);   
    }
    
    return;
}
void mexFunction(const int nlhs, mxArray *plhs[], const int nrhs, const mxArray *prhs[]) {
    bool diagAugment=false;
    size_t numRow, numCol,numBetaCols;
    mxArray *betaMatlab;
    double *A, *beta;

    if(nrhs<1){
        mexErrMsgTxt("Not enough inputs.");
    }
    
    if(nrhs>2) {
        mexErrMsgTxt("Too many inputs.");
    }
    
    if(nlhs>1) {
        mexErrMsgTxt("Too many outputs.");
    }
    
    numRow = mxGetM(prhs[0]);
    numCol = mxGetN(prhs[0]);
    
    //If an empty matrix is passed, then return an empty matrix.
    if(numRow==0||numCol==0) {
        plhs[0]=mxCreateDoubleMatrix(0,0,mxREAL);
        return;
    }

    checkRealDoubleArray(prhs[0]);

    if(nrhs>1) {
        diagAugment=getBoolFromMatlab(prhs[1]);
    }
    
    //Get the matrix.
    A=(double*)mxGetData(prhs[0]);
    
    //If we are solving the general probability problem.
    if(diagAugment==false) {
        //If we are here, then we just want general assignment probabilities,
        //not specialized to target tracking applications.
        size_t *buffer,*rows2Keep,*cols2Keep;
        size_t *buff4PermFunc;//Buffer for the permanent function.
        const size_t numRowsKept=numRow-1;
        const size_t numColsKept=numCol-1;
        size_t curRow,curCol;
        
        //Allocate the return values.
        numBetaCols=numCol;
        betaMatlab=mxCreateDoubleMatrix(numRow,numBetaCols,mxREAL);
        beta=(double*)mxGetData(betaMatlab);
        
        //Allocate the space for the indices of the rows and columns that
        //are kept in the submatrix to be passed to the permCPPSkip
        //function.
        buffer= new size_t[numRowsKept+2*numColsKept];
        rows2Keep=buffer;
        cols2Keep=rows2Keep+numRowsKept;
        buff4PermFunc=cols2Keep+numColsKept;
        
        for(curRow=0;curRow<numRow;curRow++) {
             size_t i;
             //Fill in the indices of the rows to keep.
             for(i=curRow;i<numRowsKept;i++) {
                rows2Keep[i]=i+1;
             }

             for(curCol=0;curCol<numCol;curCol++){
                 double ati=A[curRow+curCol*numRow];
                 //The A matrix removing the row and column corresponding
                 //to the selected association.
                 //Fill in the indices of the columns to keep.
                 for(i=curCol;i<numColsKept;i++) {
                    cols2Keep[i]=i+1;
                 }

                 beta[curRow+curCol*numRow]=ati*permCPPSkip(A,numRow,rows2Keep, cols2Keep, numRowsKept, numColsKept, buff4PermFunc);
                 cols2Keep[curCol]=curCol;
             }
             rows2Keep[curRow]=curRow;
        }
        
        //Delete the buffers
        delete buffer;
    }else {
        //This is the case where we are solving for target-measurement
        //assignment probabilities with missed detections.
        size_t *buffer,*rows2Keep,*cols2Keep;
        size_t *buff4PermFunc;//Buffer for the permanent function.
        const size_t numRowsKept=numRow-1;
        const size_t numColsKept=numCol-1;
        size_t numTar,numMeas;
        size_t curTar,curMeas;
        
        if(numCol<numRow) {
            mexErrMsgTxt("The number of columns cannot be less than the number of rows when diagAugment is true.");
        }

        numTar=numRow;
        numMeas=numCol-numTar;
        numBetaCols=numMeas+1;

        //Allocate the return values.
        betaMatlab=mxCreateDoubleMatrix(numRow,numBetaCols,mxREAL);
        beta=(double*)mxGetData(betaMatlab);

        //Allocate the space for the indices of the rows and columns
        //that are kept in the submatrix to be passed to the
        //permCPPSkip function.
        buffer= new size_t[numRow+2*numCol];
        rows2Keep=buffer;
        cols2Keep=rows2Keep+numRowsKept;
        buff4PermFunc=cols2Keep+numColsKept;

        for(curTar=0;curTar<numTar;curTar++) {
            size_t i;
            double ati;
            //Fill in the indices of the rows to keep.
            for(i=curTar;i<numRowsKept;i++) {
                rows2Keep[i]=i+1;
            }
            
            for(curMeas=0;curMeas<numMeas;curMeas++) {
                //The measurement hypotheses
                ati=A[curTar+curMeas*numRow];
                //The A matrix removing the row and column corresponding
                //to the selected association.
                //Fill in the indices of the columns to keep.
                for(i=curMeas;i<numColsKept;i++) {
                    cols2Keep[i]=i+1;
                }

                beta[curTar+curMeas*numRow]=ati*permCPPSkip(A,numRow,rows2Keep, cols2Keep, numRowsKept, numColsKept, buff4PermFunc);
                cols2Keep[curMeas]=curMeas;
            }
            //The missed detection hypothesis
            curMeas=numMeas+curTar;
            ati=A[curTar+curMeas*numRow];
            //Fill in the indices of the columns to keep.
            for(i=numMeas;i<curMeas;i++) {
                cols2Keep[i]=i;
            }
            for(i=curMeas;i<numColsKept;i++) {
                cols2Keep[i]=i+1;
            }
            
            beta[curTar+numMeas*numRow]=ati*permCPPSkip(A,numRow,rows2Keep, cols2Keep, numRowsKept, numColsKept, buff4PermFunc);
            rows2Keep[curTar]=curTar;
        }
        //Delete the buffers
        delete buffer;
    }
    
    //Normalize the return values.
    //It is faster to normalize the betas this way then to compute the
    //normalization constant by finding the permanent of the entire A
    //matrix.
    {
        double sumVal;
        size_t curRow,curCol;
        
        for(curRow=0;curRow<numRow;curRow++) {
            sumVal=0;
            //Compute the sum across the columns
            for(curCol=0;curCol<numBetaCols;curCol++) {
                sumVal+=beta[curRow+curCol*numRow];
            }
            //Normalize the value across the columns.
            for(curCol=0;curCol<numBetaCols;curCol++) {
                size_t idx=curRow+curCol*numRow;
                beta[idx]/=sumVal;
            }
        }
    }
 
    //Set the return values.
    plhs[0]=betaMatlab;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    //The Julan date in TT at the epoch used in the orbital propagation
    //algorithm: 0:00 January 1 1950
    const double epochDate=2433281.5;
    double *deltaT;
    size_t numTimes;
    double SGP4Elements[7],elementEpochTime;
    bool opsMode=0;
    char opsChar;
    bool gravityModel=0;
    gravconsttype gravConstType;
    mxArray *retMat;
    double *retVec;
    mxArray *errorMat;
    double *errorVals;

    if(nrhs<2||nrhs>6||nrhs==3) {
        mexErrMsgTxt("Incorrect number of inputs.");
        return;
    }
    
    if(nlhs>2) {
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }
    
    {
        const size_t M=mxGetM(prhs[0]);
        const size_t N=mxGetN(prhs[0]);
        if(!((M==7&&N==1)||(N==7&&M==1))) {
            mexErrMsgTxt("The SGP4 elements have the wrong dimensionality.");
            return; 
        }
    }
    
    checkRealDoubleArray(prhs[0]);
    {
        size_t i;
        double *theEls;
        theEls=(double*)mxGetData(prhs[0]);
        
        //Copy the elements into SGP4Elements, adjusting the units from SI
        //to the values used here.
        for(i=0;i<5;i++) {
            SGP4Elements[i]=theEls[i];
        }
        //The multipliation by 60 changes the value from radians per second
        //to radians per minute as desired by the SGP4 code.
        SGP4Elements[5]=theEls[5]*60.0;
        SGP4Elements[6]=theEls[6];
    }
    
    {
        const size_t M=mxGetM(prhs[1]);
        const size_t N=mxGetN(prhs[1]);
        
        if((M!=1&&N!=1)||mxIsEmpty(prhs[1])) {
            mexErrMsgTxt("The times have the wrong dimensionality.");
            return;
        }
        numTimes=std::max(M,N);
    }
    checkRealDoubleArray(prhs[1]);
    deltaT=(double*)mxGetData(prhs[1]);

    if(nrhs>2&&!mxIsEmpty(prhs[2])&&!mxIsEmpty(prhs[3])) {
        const double TT1=getDoubleFromMatlab(prhs[2]);
        const double TT2=getDoubleFromMatlab(prhs[3]);
        
        if(TT1>TT2) {
            elementEpochTime=(TT1-epochDate)+TT2;
        } else {
            elementEpochTime=(TT2-epochDate)+TT1;
        }
    } else {
        //No time is given. Make sure that the deep space propagator is not
        //going to be used. Otherwise, the time value does not matter.
        elementEpochTime=0;
        
        if(2*pi/SGP4Elements[5]>=225) {
            mexErrMsgTxt("The elements imply the use of the deep space propagator, but no time was given.");
            return;  
        }
    }
    
    if(nrhs>4) {
        opsMode=getBoolFromMatlab(prhs[4]);
    }
    
    if(opsMode==0) {
        opsChar='a';
    } else {
        opsChar='i';
    }
    
    if(nrhs>5) {
        gravityModel=getBoolFromMatlab(prhs[5]);
    }
    
    if(gravityModel==0) {
        gravConstType=wgs72;
    } else {
        gravConstType=wgs84;
    }
    
    //Allocate space for the return values
    retMat=mxCreateDoubleMatrix(6,numTimes,mxREAL);
    retVec=(double*)mxGetData(retMat);
    errorMat=mxCreateDoubleMatrix(numTimes,1,mxREAL);
    errorVals=(double*)mxGetData(errorMat);
    {
        //This will be filled with the ephemeris information needed for
        //propagating the satellite.
        elsetrec satRec;
        size_t i;
        
        sgp4init(gravConstType,//Specified WGS-84 or WGS-72
                 opsChar,
                 elementEpochTime,//Epoch time of the orbital elements.
                 SGP4Elements[6],//BSTAR drag term.
                 SGP4Elements[0],//Eccentricity
                 SGP4Elements[2],//Argument of perigee
                 SGP4Elements[1],//Inclination
                 SGP4Elements[4],//Mean anomaly
                 SGP4Elements[5],//Mean motion
                 SGP4Elements[3],//Righ ascension of the ascending node.
                 satRec);//Gets filled by the function.
                
        //Do the actual propagation.
        //The division by 60 transforms the time value from seconds to
        //minutes, as the SGP4 code wants the result in minutes.
        for(i=0;i<numTimes;i++) {
            double *r=retVec+6*i;
            double *v=retVec+6*i+3;
            int j;
            
            sgp4(gravConstType, satRec,  deltaT[i]/60.0, r,  v);
            
            //Convert the units from kilometers and kilometers per second
            //to meters and meters per second.
            for(j=0;j<3;j++) {
                r[j]=1000*r[j];
                v[j]=1000*v[j];
            }
            
            errorVals[i]=(double)satRec.error;
        }
    }
    
    //Save the result
    plhs[0]=retMat;
    
    //If the error value is desired.
    if(nlhs>1) {
        plhs[1]=errorMat;
    } else{
        mxDestroyArray(errorMat);
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    size_t i, numRows,numCols, numEls;
    double minBound, maxBound, *vals, *wrapVals;
    mxArray *retMat;
    bool mirrorWrap=false;
    
    
    if(nrhs<3){
        mexErrMsgTxt("Not enough inputs.");
        return;
    }
    
    if(nrhs>4) {
        mexErrMsgTxt("Too many inputs.");
        return;
    }
    
    if(nlhs>1) {
        mexErrMsgTxt("Too many outputs.");
        return;
    }
    
    checkRealDoubleArray(prhs[0]);
    numRows=mxGetM(prhs[0]);
    numCols=mxGetN(prhs[0]);
    numEls=numRows*numCols;
    
    //If given an empty matrix, return an empty matrix.
    if(numEls==0) {
        plhs[0]=mxCreateDoubleMatrix(0,0,mxREAL);
        return;
    }
    
    vals=(double*)mxGetData(prhs[0]);
    
    minBound=getDoubleFromMatlab(prhs[1]);
    maxBound=getDoubleFromMatlab(prhs[2]);
    
    if(maxBound<=minBound) {
        mexErrMsgTxt("the maximum bound must be less than the minimum bound.");
    }
    
    if(nrhs>3) {
        mirrorWrap=getBoolFromMatlab(prhs[3]);
    }
    
    //Allocate space for the return values.
    retMat=mxCreateDoubleMatrix(numRows,numCols,mxREAL);
    wrapVals=(double*)mxGetData(retMat);
    
    if(mirrorWrap) {
        for(i=0;i<numEls;i++) {
            wrapVals[i]=wrapRangeMirrorCPP(vals[i],minBound,maxBound);
        }
    } else {
       for(i=0;i<numEls;i++) {
            wrapVals[i]=wrapRangeCPP(vals[i],minBound,maxBound);
        }
    }
    
    plhs[0]=retMat;
}