void TreeSelect(double *bounds, int type, int *families, std::vector<double>& thetas, int *rotations, double *U, int d, unsigned int n, double *familyset, int m)
{
    int i;
    
    std::vector<double> theta(3*(d-1));
    
    switch (type)
    {
        case 0: // C-Vine (Pair-copula selection for the whole vine)
        {
            #pragma omp parallel for private(i)
            for (i=0;i<d-1;i++)
            {
                PairCopulaSelect(bounds,&families[i], &theta[3*i], &rotations[i], &U[0], &U[(i+1)*n], n, familyset, m);
            }
            break;
        }
        case 1: // D-Vine (Pair-copula selection for the first tree)
        {
            #pragma omp parallel for private(i)
            for (i=0;i<d-1;i++)
            {
                PairCopulaSelect(bounds,&families[i], &theta[3*i], &rotations[i], &U[i*n], &U[(i+1)*n], n, familyset, m);
            }
        }
    }
    
    for (i=0;i<d-1;i++)
    {
        switch(families[i]){
            case 0:
            {
                break;
            }
            case 18:
            {
                thetas.reserve(thetas.size() + 3);
                thetas.insert(thetas.end(), &theta[3*i], &theta[3*i+3]);
                break;
            }
            case 3: case 4: case 5: case 6: case 12: case 16: case 17: case 19:
            {
                thetas.reserve(thetas.size() + 2);
                thetas.insert(thetas.end(), &theta[3*i], &theta[3*i+2]);
                break;
            }
            default:
            {
                thetas.push_back(theta[3*i]);
            }
        }
    }
}
// Tree selection for higher (>2) order trees of D-Vine copulas
void TreeSelect(double *bounds, int type, int *families, std::vector<double>& thetas, int *rotations, double *H, double *V, int d, unsigned int n, double *familyset, int m)
{
    int i;
    
    std::vector<double> theta(3*(d-1));
    
    
    #pragma omp parallel for private(i)
    for (i=0;i<d-1;i++)
    {
        PairCopulaSelect(bounds,&families[i], &theta[3*i], &rotations[i], &H[i*n], &V[i*n], n, familyset, m);
    }
    
    for (i=0;i<d-1;i++)
    {
        switch(families[i]){
            case 0:
            {
                break;
            }
            case 18:
            {
                thetas.reserve(thetas.size() + 3);
                thetas.insert(thetas.end(), &theta[3*i], &theta[3*i+3]);
                break;
            }
            case 3: case 4: case 5: case 6: case 12: case 16: case 17: case 19:
            {
                thetas.reserve(thetas.size() + 2);
                thetas.insert(thetas.end(), &theta[3*i], &theta[3*i+2]);
                break;
            }
            default:
            {
                thetas.push_back(theta[3*i]);
            }
        }
    }
}
// FunctionID 11: PCSelect
void PCSelect(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
//declare variables
    double *U, *V, *Theta, *Rotation, *Family,*familyset, *bounds;
    int family, rotation;
    unsigned int n;
    int m;
    std::vector<double> theta(3);
    
//figure out dimensions
    n = (unsigned int)mxGetM(prhs[2]);
    m = (int)mxGetM(prhs[4]);
    
//associate outputs
    plhs[0] = mxCreateDoubleScalar(mxREAL);
    Family = mxGetPr(plhs[0]);
    
//associate inputs
    bounds = mxGetPr(prhs[1]);
    mxArray *U_in, *V_in;
    U_in = mxDuplicateArray(prhs[2]);
    V_in = mxDuplicateArray(prhs[3]);
    U = mxGetPr(U_in);
    V = mxGetPr(V_in);
    familyset = mxGetPr(prhs[4]);
    
    PairCopulaSelect(bounds,&family,&theta[0],&rotation,U,V,n,familyset,m);
    
    *Family = (double) family;
// Depending on the family associate outputs and upper and lower bounds
    switch(family){
        case 0:
        {
            plhs[1] = mxCreateDoubleMatrix(0, 0, mxREAL);
            plhs[2] = mxCreateDoubleMatrix(0, 0, mxREAL);
            break;
        }
        case 18:
        {
            plhs[1] = mxCreateDoubleMatrix(1,3,mxREAL);
            Theta = mxGetPr(plhs[1]);
            Theta[0] = theta[0];
            Theta[1] = theta[1];
            Theta[2] = theta[2];
            if (rotation==0)
            {
                plhs[2] = mxCreateDoubleMatrix(0, 0, mxREAL);
            }
            else
            {
                plhs[2] = mxCreateDoubleScalar(mxREAL);
                Rotation = mxGetPr(plhs[2]);
                *Rotation = (double) rotation;
            }
            break;
        }
        case 3: case 4: case 5: case 6: case 12: case 16: case 17: case 19:
        {
            plhs[1] = mxCreateDoubleMatrix(1,2,mxREAL);
            Theta = mxGetPr(plhs[1]);
            Theta[0] = theta[0];
            Theta[1] = theta[1];
            if (rotation==0)
            {
                plhs[2] = mxCreateDoubleMatrix(0, 0, mxREAL);
            }
            else
            {
                plhs[2] = mxCreateDoubleScalar(mxREAL);
                Rotation = mxGetPr(plhs[2]);
                *Rotation = (double) rotation;
            }
            break;
        }
        default:
        {
            plhs[1] = mxCreateDoubleScalar(mxREAL);
            Theta = mxGetPr(plhs[1]);
            Theta[0] = theta[0];
            if (rotation==0)
            {
                plhs[2] = mxCreateDoubleMatrix(0, 0, mxREAL);
            }
            else
            {
                plhs[2] = mxCreateDoubleScalar(mxREAL);
                Rotation = mxGetPr(plhs[2]);
                *Rotation = (double) rotation;
            }
        }
    }
    
    return;
    
}