// File: /workspace/github_cpp_makefile_star2_O3/myudelson[P]hmm-scalable/HMMProblemSt.cpp
// Function: HMMProblemSt::CycleBit(FitBitSt*)
void HMMProblemSt::CycleBit(FitBitSt *fb) {
    NCAT k, nK = this->task->nK;
    NCAT n_conv = 0;
    NDAT n_iter = 0;
    
    // inital copy parameter values to the t-1 slice
    NDAT* sizes_k = initToValue1D<NDAT>(nK, skill1_n);   // for full skill paremter vectors
    NDAT* offsets_k = init1D<NDAT>(nK);  // for full skill parameter vectors
    NCAT* blocks_k = init1D<NDAT>(nK);  // index per block
    NUMBER objval = 0.0;
    for(k=0; k<nK; k++) {
        offsets_k[k] = k*this->skill1_n;
        blocks_k[k] = k;
    }
    
    if(this->task->solver==METHOD_BW) {
        objval = computeAlphaAndPOParam(NULL); // just alpha and p(O|param)
        computeBeta();
        computeXiGamma();
    } else {
        objval = computeGradients();
        if( this->task->solver==METHOD_GD || this->task->solver==METHOD_CGD || this->task->solver==METHOD_GBB )
            fb->scaleGradients(false, this->active_set_block);
    }

    // set p(O|param) for pre-step
    fb->fit_result.pO0 = objval; // overall start before this cycle
    fb->fit_result.pO  = objval; // overall finish after this cycle
    if( fb->fit_result.pO0_prefit == -1.0 ) {
        fb->fit_result.pO0_prefit = objval; // overall before fitting started
    }
    for(k=0; k<nK; k++) {
        if(n_iter==0) {
            fb->fit_results[k].pO0 = this->loglik_k[k];
            fb->fit_results[k].pO  = this->loglik_k[k];
            if( fb->fit_results[k].pO0_prefit == -1.0 ) {
                fb->fit_results[k].pO0_prefit = this->loglik_k[k];
                fb->fit_results[k].ndat = this->ndat_k[k];
            }
        }
    }
    while( n_conv!=nK && n_iter<=this->task->maxiter ) {
        // save t-1, t-2 (tm1, tm2) values before making the step or updating the gradient
        cpy1D(fb->PARAMm1, fb->PARAMm2, fb->nPARAM);
        cpy1D(fb->PARAM, fb->PARAMm1, fb->nPARAM);
        if( this->task->solver==METHOD_CGD || this->task->solver==METHOD_GBB)
            cpy1D(fb->GRAD, fb->GRADm1, fb->nPARAM);
        // for congugate gradient descent – work with direction
        if (this->task->solver==METHOD_CGD) {
            if( n_iter==0 ) {
                cpy1D(fb->GRAD, fb->DIR, fb->nPARAM); // copy to DIR
                negate1D(fb->DIR, fb->nPARAM);
            }
            else
                cpy1D(fb->DIR, fb->DIRm1, fb->nPARAM);// fb->copy(FBS_DIR,  FBS_DIRm1);
        }

        
        // Make the step
        if( this->task->solver==METHOD_GD || (n_iter==0 && this->task->solver==METHOD_CGD)  || (n_iter==1 && this->task->solver==METHOD_GBB) )
            doLinearStep(fb, false/*direction*/);
        else if( this->task->solver==METHOD_CGD )
            doConjugateLinearStep(fb);
        else if( this->task->solver==METHOD_GDL )
            doLagrangeStep(fb);
        else if( this->task->solver==METHOD_GBB )
            doBarzilaiBorweinStep(fb);
        else if( this->task->solver==METHOD_BW )
            doBaumWelchStep(fb);
        
        // project to simplex with boundaries if necessary
        fb->projectToSimplex( this->non01constraints, this->active_set_block );
        // check factual convergence (without considering connectivity yet)
        n_conv = fb->checkConvergence(nK, offsets_k, sizes_k, blocks_k, this->active_set_block);

        // decide on active set (propagate dependencies)
        // this->task->connectivities[0] skill-skill
//        NDAT set0to1 = 0; // DEBUG
        for(k=0; k<nK; k++) {
            if( this->active_set_block[k]==1 ) {
                for(NCAT l=0; l<=nK; l++) {
                    if(l!=k && this->task->connectivities[0][k][l]==1) {
//                        if(this->active_set_block[l]==0) set0to1++; // DEBUG
                        this->active_set_block[l] = 1;
                    }
                } // for all potential skills
            } // if the skill is active
        }
//        fprintf(stderr,"[debug] Activated skills %d.\n", set0to1); // DEBUG

        // copy parameter values after we already compared step t-1 with currently computed step t
        // cpy1D(fb->PARAMm1, fb->PARAMm2, fb->nPARAM);
        // cpy1D(fb->PARAM, fb->PARAMm1, fb->nPARAM);
        // for Gradient Descent METHOD_GD, no extra copying
        // if Conjugate Gradient and Barzilain Borwein – copy previous gradient
//        if( this->task->solver==METHOD_CGD || this->task->solver==METHOD_GBB)
//            cpy1D(fb->GRAD, fb->GRADm1, fb->nPARAM);
//        // for congugate gradient descent – work with direction
//        if (this->task->solver==METHOD_CGD) {
//            if( n_iter==0 ) {
//                cpy1D(fb->GRAD, fb->DIRm1, fb->nPARAM);
//                negate1D(fb->DIRm1, fb->nPARAM);
//            }
//            else
//                cpy1D(fb->DIR, fb->DIRm1, fb->nPARAM);// fb->copy(FBS_DIR,  FBS_DIRm1);
//        }

        // move this into the stepper vvvvvv
//        for(k=0; k<=nK; k++) {
//            fb->fit_results[k].iter = n_iter;
//            //frs[k].pOmid = frs[k].pO;
//        }
        // compute p(O|param) post-step after projecting
        if(this->task->solver==METHOD_BW) {
            objval = computeAlphaAndPOParam(NULL); // just alpha and p(O|param)
            computeBeta();
            computeXiGamma();
        } else {
            objval = computeGradients();
            if( this->task->solver==METHOD_GD || this->task->solver==METHOD_CGD || this->task->solver==METHOD_GBB )
                fb->scaleGradients(false, this->active_set_block);
        }
        
        // update objective function & count iterations
        fb->fit_result.pO = objval;
        for(k=0; k<nK; k++) {
            // update objective
            if(this->active_set_block[k]>0) {
                fb->fit_results[k].pO0 = fb->fit_results[k].pO;
                fb->fit_results[k].pO = this->loglik_k[k];
                fb->fit_results[k].iter++;
            }
        }
        n_iter++;
    }// single skill loop
    fb->fit_result.iter = n_iter;
    // this is the case when 2 steps lead to step back to the initial value, i.e. oscillation
    // the code below doesn' make anny sense yet to me.s
//    for(k=0; k<=nK; k++) {
//        if(fb->fit_results[k].iter==2 && fb->fit_results[k].conv && fb->checkConvergenceBitSingle(offsets_k[k], sizes_k[k], &fb->fit_results[0])) {
//            // decrease iteration counter to 1
//            fb->fit_results[k].iter--;
//        }
//        fb->fit_results[k].pO = this->loglik_k[k];
//    }
    free(offsets_k);
    free(sizes_k);
    free(blocks_k);
    return;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
movq %rsi, %rbx
movq %rdi, %r15
movq 0x68(%rdi), %r14
movslq 0x908(%r14), %r12
movl 0x38(%rdi), %ebp
movl $0x4, %esi
movq %r12, %rdi
callq 0x2110
testq %r12, %r12
jle 0xea76
leal 0x3(%r12), %esi
leaq -0x1(%r12), %rcx
movq %rcx, %xmm0
pshufd $0x44, %xmm0, %xmm0     # xmm0 = xmm0[0,1,0,1]
shrl $0x2, %esi
shlq $0x4, %rsi
movdqa 0x48d3(%rip), %xmm1     # 0x13280
movdqa 0x448b(%rip), %xmm2     # 0x12e40
xorl %ecx, %ecx
movdqa 0x4491(%rip), %xmm3     # 0x12e50
pxor %xmm3, %xmm0
pcmpeqd %xmm4, %xmm4
movdqa 0x48c1(%rip), %xmm5     # 0x13290
movdqa %xmm2, %xmm6
pxor %xmm3, %xmm6
movdqa %xmm6, %xmm7
pcmpgtd %xmm0, %xmm7
pcmpeqd %xmm0, %xmm6
pshufd $0xf5, %xmm6, %xmm8     # xmm8 = xmm6[1,1,3,3]
pand %xmm7, %xmm8
pshufd $0xf5, %xmm7, %xmm6     # xmm6 = xmm7[1,1,3,3]
por %xmm8, %xmm6
movd %xmm6, %edx
notl %edx
testb $0x1, %dl
je 0xea06
movl %ebp, (%rax,%rcx)
pxor %xmm4, %xmm6
pextrw $0x4, %xmm6, %edx
testb $0x1, %dl
je 0xea18
movl %ebp, 0x4(%rax,%rcx)
movdqa %xmm1, %xmm6
pxor %xmm3, %xmm6
movdqa %xmm6, %xmm7
pcmpgtd %xmm0, %xmm7
pcmpeqd %xmm0, %xmm6
pshufd $0xf5, %xmm6, %xmm8     # xmm8 = xmm6[1,1,3,3]
pand %xmm7, %xmm8
pshufd $0xf5, %xmm7, %xmm6     # xmm6 = xmm7[1,1,3,3]
por %xmm8, %xmm6
pxor %xmm4, %xmm6
pextrw $0x0, %xmm6, %edx
testb $0x1, %dl
je 0xea53
movl %ebp, 0x8(%rax,%rcx)
pextrw $0x4, %xmm6, %edx
testb $0x1, %dl
je 0xea61
movl %ebp, 0xc(%rax,%rcx)
paddq %xmm5, %xmm2
paddq %xmm5, %xmm1
addq $0x10, %rcx
cmpq %rcx, %rsi
jne 0xe9cf
movq %rax, 0x20(%rsp)
movl $0x4, %esi
movq %r12, %rdi
callq 0x2110
movq %rax, %r13
movl $0x4, %esi
movq %r12, %rdi
callq 0x2110
testl %r12d, %r12d
jle 0xeab3
xorl %edx, %edx
xorl %ecx, %ecx
movl %edx, (%r13,%rcx,4)
movl %ecx, (%rax,%rcx,4)
incq %rcx
addl %ebp, %edx
cmpq %rcx, %r12
jne 0xeaa1
movq %rax, 0x10(%rsp)
cmpb $0x1, 0x4f(%r14)
jne 0xeae0
movq %r15, %rdi
xorl %esi, %esi
callq 0xb8ee
movq %xmm0, (%rsp)
movq %r15, %rdi
callq 0xc57e
movq %r15, %rdi
callq 0xc884
jmp 0xeb16
movq (%r15), %rax
movq %r15, %rdi
callq *0x80(%rax)
movq 0x68(%r15), %rax
movzbl 0x4f(%rax), %eax
cmpl $0x5, %eax
ja 0xeb1b
movl $0x2c, %ecx
btl %eax, %ecx
jae 0xeb1b
movq 0x58(%r15), %rdx
movq %rbx, %rdi
xorl %esi, %esi
movq %xmm0, (%rsp)
callq 0x806a
movq (%rsp), %xmm0
movq %xmm0, 0x70(%rbx)
movq %xmm0, 0x78(%rbx)
movsd 0x68(%rbx), %xmm1
ucomisd 0x3e16(%rip), %xmm1     # 0x12948
jne 0xeb3b
jp 0xeb3b
movq %xmm0, 0x68(%rbx)
testl %r12d, %r12d
jle 0xeb96
movq 0x80(%r15), %rax
movq 0x88(%r15), %rcx
movq 0x58(%rbx), %rdx
addq $0x8, %rdx
xorl %esi, %esi
movsd 0x3de8(%rip), %xmm0     # 0x12948
movsd (%rax,%rsi,8), %xmm1
movsd %xmm1, 0x8(%rdx)
movsd %xmm1, 0x10(%rdx)
movsd (%rdx), %xmm1
ucomisd %xmm0, %xmm1
jne 0xeb8a
jp 0xeb8a
movsd (%rax,%rsi,8), %xmm1
movsd %xmm1, (%rdx)
movl (%rcx,%rsi,4), %edi
movl %edi, 0x1c(%rdx)
incq %rsi
addq $0x28, %rdx
cmpq %rsi, %r12
jne 0xeb60
movq %r13, 0x18(%rsp)
testl %r12d, %r12d
je 0xee50
leal 0x1(%r12), %r14d
movl %r12d, %ebp
xorl %r13d, %r13d
movq 0x68(%r15), %rax
cmpl 0x48(%rax), %r13d
jg 0xee53
movq 0x18(%rbx), %rsi
movq 0x20(%rbx), %rdi
movslq 0xc(%rbx), %rdx
shlq $0x3, %rdx
callq 0x2180
movq 0x10(%rbx), %rsi
movq 0x18(%rbx), %rdi
movslq 0xc(%rbx), %rdx
shlq $0x3, %rdx
callq 0x2180
movq 0x68(%r15), %rax
movzbl 0x4f(%rax), %eax
cmpl $0x5, %eax
je 0xebf9
cmpl $0x3, %eax
jne 0xec15
movq 0x30(%rbx), %rsi
movq 0x38(%rbx), %rdi
movslq 0xc(%rbx), %rdx
shlq $0x3, %rdx
callq 0x2180
movq 0x68(%r15), %rax
movb 0x4f(%rax), %al
cmpb $0x3, %al
jne 0xec6f
movslq 0xc(%rbx), %rdx
shlq $0x3, %rdx
testl %r13d, %r13d
je 0xec35
movq 0x48(%rbx), %rsi
movq 0x50(%rbx), %rdi
callq 0x2180
jmp 0xec6f
movq 0x30(%rbx), %rsi
movq 0x48(%rbx), %rdi
callq 0x2180
movslq 0xc(%rbx), %rax
testq %rax, %rax
movapd 0x3d4f(%rip), %xmm1     # 0x129a0
jle 0xec6f
movq 0x48(%rbx), %rcx
xorl %edx, %edx
movsd (%rcx,%rdx,8), %xmm0
xorpd %xmm1, %xmm0
movlpd %xmm0, (%rcx,%rdx,8)
incq %rdx
cmpq %rdx, %rax
jne 0xec59
movq 0x68(%r15), %rax
movzbl 0x4f(%rax), %eax
cmpl $0x2, %eax
je 0xec97
testl %r13d, %r13d
jne 0xec85
cmpb $0x3, %al
je 0xec97
cmpl $0x1, %r13d
jne 0xede5
cmpb $0x5, %al
jne 0xede5
movq (%r15), %rax
movq %r15, %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq *0xa0(%rax)
movzbl 0x50(%r15), %esi
movq 0x58(%r15), %rdx
movq %rbx, %rdi
callq 0x8114
movq 0x58(%r15), %r9
movq %rbx, %rdi
movl %r12d, %esi
movq 0x18(%rsp), %rdx
movq 0x20(%rsp), %rcx
movq 0x10(%rsp), %r8
callq 0x7f36
movl %eax, (%rsp)
testl %r12d, %r12d
jle 0xed22
xorl %eax, %eax
movq 0x58(%r15), %rcx
cmpb $0x1, (%rcx,%rax)
jne 0xed1a
xorl %ecx, %ecx
cmpq %rcx, %rax
je 0xed12
movq 0x68(%r15), %rdx
movq 0x8f0(%rdx), %rdx
movq (%rdx), %rdx
movq (%rdx,%rax,8), %rdx
cmpb $0x1, (%rdx,%rcx)
jne 0xed12
movq 0x58(%r15), %rdx
movb $0x1, (%rdx,%rcx)
incq %rcx
cmpq %rcx, %r14
jne 0xeced
incq %rax
cmpq %rbp, %rax
jne 0xece1
movq 0x68(%r15), %rax
cmpb $0x1, 0x4f(%rax)
jne 0xed4e
movq %r15, %rdi
xorl %esi, %esi
callq 0xb8ee
movq %xmm0, 0x8(%rsp)
movq %r15, %rdi
callq 0xc57e
movq %r15, %rdi
callq 0xc884
jmp 0xed85
movq (%r15), %rax
movq %r15, %rdi
callq *0x80(%rax)
movq 0x68(%r15), %rax
movzbl 0x4f(%rax), %eax
cmpl $0x5, %eax
ja 0xed8b
movl $0x2c, %ecx
btl %eax, %ecx
jae 0xed8b
movq 0x58(%r15), %rdx
movq %rbx, %rdi
xorl %esi, %esi
movq %xmm0, 0x8(%rsp)
callq 0x806a
movq 0x8(%rsp), %xmm0
movq %xmm0, 0x78(%rbx)
testl %r12d, %r12d
jle 0xedd6
movq 0x58(%r15), %rax
movq 0x80(%r15), %rcx
movl $0x18, %edx
xorl %esi, %esi
cmpb $0x0, (%rax,%rsi)
jle 0xedca
movq 0x58(%rbx), %rdi
movsd (%rdi,%rdx), %xmm0
movsd %xmm0, -0x8(%rdi,%rdx)
movq (%rcx,%rsi,8), %xmm0
movq %xmm0, (%rdi,%rdx)
incl -0x18(%rdi,%rdx)
incq %rsi
addq $0x28, %rdx
cmpq %rsi, %rbp
jne 0xeda7
incl %r13d
cmpl %r12d, (%rsp)
jne 0xebaf
jmp 0xee53
decl %eax
cmpl $0x4, %eax
ja 0xeca8
leaq 0x44a9(%rip), %rcx      # 0x132a0
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq (%r15), %rax
movq %r15, %rdi
movq %rbx, %rsi
callq *0xb8(%rax)
jmp 0xeca8
movq (%r15), %rax
movq %r15, %rdi
movq %rbx, %rsi
callq *0xa8(%rax)
jmp 0xeca8
movq (%r15), %rax
movq %r15, %rdi
movq %rbx, %rsi
callq *0xb0(%rax)
jmp 0xeca8
movq (%r15), %rax
movq %r15, %rdi
movq %rbx, %rsi
callq *0xc0(%rax)
jmp 0xeca8
xorl %r13d, %r13d
movl %r13d, 0x60(%rbx)
movq 0x18(%rsp), %rdi
callq 0x2240
movq 0x20(%rsp), %rdi
callq 0x2240
movq 0x10(%rsp), %rdi
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2240
nop