// File: jmmccracken[P]PAI/ccmsrc.cpp
// Function: FindEmbeddingDimension(double*, int, int, double, int, bool)
int FindEmbeddingDimension(double dX[],int iXlength,int iNumberOfTimeStep2Check,double dWeightToleranceLevel,int iLagTime,bool bVerboseFlag){

    //Set the max embedding dimension to check (to save computation time)
    int iMaxEDim = (iXlength/2);

    //Find minimum size of possible shadow manifolds and report a warning
    //if the requested number of time step checks is too large
    int iCalShadManDimMin = iXlength-((iMaxEDim-1)*iLagTime);
    if( iNumberOfTimeStep2Check > iCalShadManDimMin ){
        fprintf(stderr,"Warning in FindEmbeddingDimension(): the requested number of time step checks is too large; setting the value to %i\n",iCalShadManDimMin);
        iNumberOfTimeStep2Check = iCalShadManDimMin;
    }

    int iCutoffEDimForEachTimeStep[iNumberOfTimeStep2Check];
    for(int iter=0;iter < iNumberOfTimeStep2Check;iter++ ){
        iCutoffEDimForEachTimeStep[iter] = iMaxEDim;
    }

    if( bVerboseFlag ){
        fprintf(stderr,"-- FindEmbeddingDimension() verbose output begin --\n");
    }

    //Loop through the requested number of delay vectors to find the weights
    for(int iDelayVectorN = 1; iDelayVectorN <= iNumberOfTimeStep2Check;iDelayVectorN++ ){

        for(int iEstep = 2;iEstep < iMaxEDim;iEstep++ ){

            //Find calculated shadow manifold dimension
            int iCalShadManDim = iXlength-((iEstep-1)*iLagTime);

            //Assign some memory for the shadow manifold
            double** dXShadow;
            dXShadow = new double*[iCalShadManDim];
            for(int iter = 0;iter < iCalShadManDim;iter++ ){
                dXShadow[iter] = new double[iEstep];
            }
            int iTstep4delayvector;

            //Create the shadow manifold by creating the delay vectors sequentially
            for(int iShadowStep = 1; iShadowStep <= iCalShadManDim;iShadowStep++ ){
                iTstep4delayvector = iShadowStep+((iEstep-1)*iLagTime);
                for(int iDimStep = 1; iDimStep <= iEstep; iDimStep++ ){
                    dXShadow[iShadowStep-1][iDimStep-1] = dX[(iTstep4delayvector-((iDimStep-1)*iLagTime))-1];
                }
            }

            //Storage for sorting, calculating, and organizing
            double dDelayVectorOfInterest[iEstep],  //delay vector currently being compared
                   dWeights[(iEstep+1)],  //weights to contruct Y estimate
                   dYEstimateGivenX[iCalShadManDim];  //estimated Y used the shadow manifold of X

            int iTstepOfNearestNeighborsTempRow[iEstep+1];  //time steps of nearest neighbor delay vectors

            //Populate the temp delay vector
            for(int iCopyStep = 0; iCopyStep < iEstep; iCopyStep++ ){
                dDelayVectorOfInterest[iCopyStep] = dXShadow[iDelayVectorN-1][iCopyStep];
            }

            FindWeightsFromShadow(dWeights,iTstepOfNearestNeighborsTempRow,dDelayVectorOfInterest,dXShadow,iCalShadManDim,iEstep,iLagTime,iEstep);

            //Free the dXshadow memory
            for(int iter = 0;iter < iCalShadManDim;iter++ ){
                delete dXShadow[iter];
            }
            delete dXShadow;

            //Check weights
            for(int iWstep = 0;iWstep < (iEstep+1);iWstep++ ){
                if( dWeights[iWstep] < dWeightToleranceLevel ){
                    iCutoffEDimForEachTimeStep[iDelayVectorN] = iEstep;
                    iEstep = (iXlength/2)+1; //break out of the loop over embedding dimensions
                }
                if( bVerboseFlag ){
                    fprintf(stderr,"t = %i;E = %i; weight %i = %.20f (tol = %.20f)\n",iDelayVectorN,iEstep,iWstep,dWeights[iWstep],dWeightToleranceLevel);
                }
            }
        }
    }

   if( bVerboseFlag ){
        fprintf(stderr,"Cutoff embedding dimensions for each time step:\n");
        for(int iter=0;iter < iNumberOfTimeStep2Check;iter++ ){
            fprintf(stderr,"%i\n",iCutoffEDimForEachTimeStep[iter]);
        }
   }
   if( bVerboseFlag ){
       fprintf(stderr,"-- FindEmbeddingDimension() verbose output end --\n");
   }

   bool bCheck = true;
   for(int iter=0;iter < iNumberOfTimeStep2Check;iter++ ){
        if( iCutoffEDimForEachTimeStep[iter] == iMaxEDim){
                bCheck &= true;
        }
   }
    if( bCheck ){
        fprintf(stderr,"Warning in FindEmbeddingDimension(): cutoff dimension may have maxed out\n");
    }

    //Find and return mode
    int iEDimMode = iMode(iCutoffEDimForEachTimeStep,iNumberOfTimeStep2Check);
    return(iEDimMode);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xe0, %rsp
movb %r8b, %al
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movl %edx, -0x10(%rbp)
movsd %xmm0, -0x18(%rbp)
movl %ecx, -0x1c(%rbp)
andb $0x1, %al
movb %al, -0x1d(%rbp)
movl -0xc(%rbp), %eax
movl $0x2, %ecx
cltd
idivl %ecx
movl %eax, -0x24(%rbp)
movl -0xc(%rbp), %eax
movl -0x24(%rbp), %ecx
subl $0x1, %ecx
imull -0x1c(%rbp), %ecx
subl %ecx, %eax
movl %eax, -0x28(%rbp)
movl -0x10(%rbp), %eax
cmpl -0x28(%rbp), %eax
jle 0x398e
movq 0x15654(%rip), %rax     # 0x18fc8
movq (%rax), %rdi
movl -0x28(%rbp), %edx
leaq 0xc8a3(%rip), %rsi      # 0x10224
movb $0x0, %al
callq 0x32a0
movl -0x28(%rbp), %eax
movl %eax, -0x10(%rbp)
movl -0x10(%rbp), %eax
movq %rsp, %rcx
movq %rcx, -0x30(%rbp)
leaq 0xf(,%rax,4), %rdx
andq $-0x10, %rdx
movq %rsp, %rcx
subq %rdx, %rcx
movq %rcx, -0xb0(%rbp)
movq %rcx, %rsp
movq %rax, -0x38(%rbp)
movl $0x0, -0x3c(%rbp)
movl -0x3c(%rbp), %eax
cmpl -0x10(%rbp), %eax
jge 0x39e3
movq -0xb0(%rbp), %rax
movl -0x24(%rbp), %edx
movslq -0x3c(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movl -0x3c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x3c(%rbp)
jmp 0x39bf
testb $0x1, -0x1d(%rbp)
je 0x3a01
movq 0x155d8(%rip), %rax     # 0x18fc8
movq (%rax), %rdi
leaq 0xc89f(%rip), %rsi      # 0x10299
movb $0x0, %al
callq 0x32a0
movl $0x1, -0x40(%rbp)
movl -0x40(%rbp), %eax
cmpl -0x10(%rbp), %eax
jg 0x3da4
movl $0x2, -0x44(%rbp)
movl -0x44(%rbp), %eax
cmpl -0x24(%rbp), %eax
jge 0x3d94
movl -0xc(%rbp), %eax
movl -0x44(%rbp), %ecx
subl $0x1, %ecx
imull -0x1c(%rbp), %ecx
subl %ecx, %eax
movl %eax, -0x48(%rbp)
movslq -0x48(%rbp), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x3030
movq %rax, -0x50(%rbp)
movl $0x0, -0x54(%rbp)
movl -0x54(%rbp), %eax
cmpl -0x48(%rbp), %eax
jge 0x3ab0
movslq -0x44(%rbp), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
seto %cl
movq $-0x1, %rax
testb $0x1, %cl
cmovneq %rax, %rdi
callq 0x3030
movq %rax, %rdx
movq -0x50(%rbp), %rax
movslq -0x54(%rbp), %rcx
movq %rdx, (%rax,%rcx,8)
movl -0x54(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x54(%rbp)
jmp 0x3a69
movl $0x1, -0x5c(%rbp)
movl -0x5c(%rbp), %eax
cmpl -0x48(%rbp), %eax
jg 0x3b35
movl -0x5c(%rbp), %eax
movl -0x44(%rbp), %ecx
subl $0x1, %ecx
imull -0x1c(%rbp), %ecx
addl %ecx, %eax
movl %eax, -0x58(%rbp)
movl $0x1, -0x60(%rbp)
movl -0x60(%rbp), %eax
cmpl -0x44(%rbp), %eax
jg 0x3b28
movq -0x8(%rbp), %rax
movl -0x58(%rbp), %ecx
movl -0x60(%rbp), %edx
subl $0x1, %edx
imull -0x1c(%rbp), %edx
subl %edx, %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
movsd (%rax,%rcx,8), %xmm0
movq -0x50(%rbp), %rax
movl -0x5c(%rbp), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movl -0x60(%rbp), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
movsd %xmm0, (%rax,%rcx,8)
movl -0x60(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x60(%rbp)
jmp 0x3ad8
jmp 0x3b2a
movl -0x5c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x5c(%rbp)
jmp 0x3ab7
movl -0x44(%rbp), %eax
movq %rsp, %rcx
movq %rcx, -0x68(%rbp)
leaq 0xf(,%rax,8), %rdx
andq $-0x10, %rdx
movq %rsp, %rcx
subq %rdx, %rcx
movq %rcx, -0xc8(%rbp)
movq %rcx, %rsp
movq %rax, -0x70(%rbp)
movl -0x44(%rbp), %eax
incl %eax
leaq 0xf(,%rax,8), %rdx
andq $-0x10, %rdx
movq %rsp, %rcx
subq %rdx, %rcx
movq %rcx, -0xc0(%rbp)
movq %rcx, %rsp
movq %rax, -0x78(%rbp)
movl -0x48(%rbp), %eax
leaq 0xf(,%rax,8), %rdx
andq $-0x10, %rdx
movq %rsp, %rcx
subq %rdx, %rcx
movq %rcx, %rsp
movq %rax, -0x80(%rbp)
movl -0x44(%rbp), %eax
incl %eax
leaq 0xf(,%rax,4), %rdx
andq $-0x10, %rdx
movq %rsp, %rcx
subq %rdx, %rcx
movq %rcx, -0xb8(%rbp)
movq %rcx, %rsp
movq %rax, -0x88(%rbp)
movl $0x0, -0x8c(%rbp)
movl -0x8c(%rbp), %eax
cmpl -0x44(%rbp), %eax
jge 0x3c1e
movq -0xc8(%rbp), %rax
movq -0x50(%rbp), %rcx
movl -0x40(%rbp), %edx
subl $0x1, %edx
movslq %edx, %rdx
movq (%rcx,%rdx,8), %rcx
movslq -0x8c(%rbp), %rdx
movsd (%rcx,%rdx,8), %xmm0
movslq -0x8c(%rbp), %rcx
movsd %xmm0, (%rax,%rcx,8)
movl -0x8c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x8c(%rbp)
jmp 0x3bd2
movq -0xc8(%rbp), %rdx
movq -0xb8(%rbp), %rsi
movq -0xc0(%rbp), %rdi
movq -0x50(%rbp), %rcx
movl -0x48(%rbp), %r8d
movl -0x44(%rbp), %r9d
movl -0x1c(%rbp), %r10d
movl -0x44(%rbp), %eax
subq $0x10, %rsp
movl %r10d, (%rsp)
movl %eax, 0x8(%rsp)
callq 0x3ee0
addq $0x10, %rsp
movl $0x0, -0x90(%rbp)
movl -0x90(%rbp), %eax
cmpl -0x48(%rbp), %eax
jge 0x3cab
movq -0x50(%rbp), %rax
movslq -0x90(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0xd0(%rbp)
cmpq $0x0, %rax
je 0x3c98
movq -0xd0(%rbp), %rdi
callq 0x3200
jmp 0x3c9a
movl -0x90(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x90(%rbp)
jmp 0x3c65
movq -0x50(%rbp), %rax
movq %rax, -0xd8(%rbp)
cmpq $0x0, %rax
je 0x3cc8
movq -0xd8(%rbp), %rdi
callq 0x3200
movl $0x0, -0x94(%rbp)
movl -0x94(%rbp), %eax
movl -0x44(%rbp), %ecx
addl $0x1, %ecx
cmpl %ecx, %eax
jge 0x3d7f
movq -0xc0(%rbp), %rax
movslq -0x94(%rbp), %rcx
movsd (%rax,%rcx,8), %xmm1
movsd -0x18(%rbp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x3d26
movq -0xb0(%rbp), %rax
movl -0x44(%rbp), %edx
movslq -0x40(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
movl -0xc(%rbp), %eax
movl $0x2, %ecx
cltd
idivl %ecx
addl $0x1, %eax
movl %eax, -0x44(%rbp)
testb $0x1, -0x1d(%rbp)
je 0x3d69
movq -0xc0(%rbp), %rax
movq 0x1528e(%rip), %rcx     # 0x18fc8
movq (%rcx), %rdi
movl -0x40(%rbp), %edx
movl -0x44(%rbp), %ecx
movl -0x94(%rbp), %r8d
movslq -0x94(%rbp), %rsi
movsd (%rax,%rsi,8), %xmm0
movsd -0x18(%rbp), %xmm1
leaq 0xc56c(%rip), %rsi      # 0x102ce
movb $0x2, %al
callq 0x32a0
jmp 0x3d6b
movl -0x94(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x94(%rbp)
jmp 0x3cd2
movq -0x68(%rbp), %rax
movq %rax, %rsp
movl -0x44(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x44(%rbp)
jmp 0x3a1b
jmp 0x3d96
movl -0x40(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x40(%rbp)
jmp 0x3a08
testb $0x1, -0x1d(%rbp)
je 0x3e13
movq 0x15217(%rip), %rax     # 0x18fc8
movq (%rax), %rdi
leaq 0xc543(%rip), %rsi      # 0x102fe
movb $0x0, %al
callq 0x32a0
movl $0x0, -0x98(%rbp)
movl -0x98(%rbp), %eax
cmpl -0x10(%rbp), %eax
jge 0x3e11
movq -0xb0(%rbp), %rax
movq 0x151e3(%rip), %rcx     # 0x18fc8
movq (%rcx), %rdi
movslq -0x98(%rbp), %rcx
movl (%rax,%rcx,4), %edx
leaq 0xc835(%rip), %rsi      # 0x1062e
movb $0x0, %al
callq 0x32a0
movl -0x98(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x98(%rbp)
jmp 0x3dcc
jmp 0x3e13
testb $0x1, -0x1d(%rbp)
je 0x3e31
movq 0x151a8(%rip), %rax     # 0x18fc8
movq (%rax), %rdi
leaq 0xc505(%rip), %rsi      # 0x1032f
movb $0x0, %al
callq 0x32a0
movb $0x1, -0x99(%rbp)
movl $0x0, -0xa0(%rbp)
movl -0xa0(%rbp), %eax
cmpl -0x10(%rbp), %eax
jge 0x3e92
movq -0xb0(%rbp), %rax
movslq -0xa0(%rbp), %rcx
movl (%rax,%rcx,4), %eax
cmpl -0x24(%rbp), %eax
jne 0x3e7f
movb -0x99(%rbp), %al
andb $0x1, %al
movzbl %al, %eax
andl $0x1, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movb %al, -0x99(%rbp)
jmp 0x3e81
movl -0xa0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xa0(%rbp)
jmp 0x3e42
testb $0x1, -0x99(%rbp)
je 0x3eb3
movq 0x15126(%rip), %rax     # 0x18fc8
movq (%rax), %rdi
leaq 0xc4b6(%rip), %rsi      # 0x10362
movb $0x0, %al
callq 0x32a0
movq -0xb0(%rbp), %rdi
movl -0x10(%rbp), %esi
callq 0x4220
movl %eax, -0xa4(%rbp)
movl -0xa4(%rbp), %eax
movq -0x30(%rbp), %rcx
movq %rcx, %rsp
movq %rbp, %rsp
popq %rbp
retq
nopw (%rax,%rax)