// File: /workspace/github_c_makefile_star2_O3/debbiemarkslab[P]plmc/src/inference.c
// Function: InferPairModel
numeric_t *InferPairModel(alignment_t *ali, options_t *options) {
    /* Estimate the parameters of a maximum entropy model for a
       multiple sequence alignment */

    /* Initialize the regularization parameters */
    numeric_t *lambdas =
    (numeric_t *) malloc((ali->nSites + ali->nSites * (ali->nSites - 1) / 2)
            * sizeof(numeric_t));
    for (int i = 0; i < ali->nSites; i++) lambdaHi(i) = options->lambdaH;
    for (int i = 0; i < ali->nSites - 1; i++)
        for (int j = i + 1; j < ali->nSites; j++)
            lambdaEij(i, j) = options->lambdaE;

    /* For gap-reduced problems, eliminate the gaps and reduce the alphabet */
    if (options->estimatorMAP == INFER_MAP_PLM_GAPREDUCE) {
        ali->nCodes = strlen(ali->alphabet) - 1;
        for (int i = 0; i < ali->nSites; i++)
            for (int s = 0; s < ali->nSeqs; s++)
                seq(s, i) -= 1;
    }

    /* Initialize parameters */
    ali->nParams = ali->nSites * ali->nCodes
        + ali->nSites * (ali->nSites - 1) / 2 * ali->nCodes * ali->nCodes;
    numeric_t *x = (numeric_t *) malloc(sizeof(numeric_t) * ali->nParams);
    if (x == NULL) {
        fprintf(stderr,
            "ERROR: Failed to allocate a memory block for variables.\n");
        exit(1);
    }
    for (int i = 0; i < ali->nParams; i++) x[i] = 0.0;

    /* Initialize site parameters with the ML estimates 
        hi = log(fi) + C
        A single pseudocount is added for stability 
       (Laplace's rule or Morcos et al. with lambda = nCodes) */
    if (options->zeroAPC != 1) {
        for (int i = 0; i < ali->nSites; i++)
            for (int ai = 0; ai < ali->nCodes; ai++)
                xHi(i, ai) = log(fi(i, ai) * ali->nEff + 1.0);
        /* Zero-sum gauge */
        for (int i = 0; i < ali->nSites; i++) {
            numeric_t hSum = 0.0;
            for (int ai = 0; ai < ali->nCodes; ai++) hSum += xHi(i, ai);
            numeric_t hShift = hSum / (numeric_t) ali->nCodes;
            for (int ai = 0; ai < ali->nCodes; ai++)
                xHi(i, ai) -= hShift;
        }
    }

    switch(options->estimator) {
        /* Point estimates */
        case INFER_MAP:
            /* Maximum a posteriori estimates of model parameters */
            EstimatePairModelMAP(x, lambdas, ali, options);
            break;
        /* For: future alternative estimators */
        default:
            /* Maximum a posteriori estimates of model parameters */
            EstimatePairModelMAP(x, lambdas, ali, options);
    }

    /* Restore the alignment encoding after inference */
    if (options->estimatorMAP == INFER_MAP_PLM_GAPREDUCE) {
        for (int i = 0; i < ali->nSites; i++)
            for (int s = 0; s < ali->nSeqs; s++)
                seq(s, i) += 1;
    }

    return (numeric_t *) x;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movq %rsi, %r15
movq %rdi, %rbx
movslq 0x4(%rdi), %r13
leal -0x1(%r13), %r14d
movl %r14d, %eax
imull %r13d, %eax
movl %eax, %ebp
shrl $0x1f, %ebp
addl %eax, %ebp
sarl %ebp
leal (%rbp,%r13), %eax
movslq %eax, %rdi
shlq $0x3, %rdi
callq 0x11b0
movq %rax, %r12
testq %r13, %r13
jle 0x71fc
movsd 0x40(%r15), %xmm0
leal 0x1(%r13), %eax
movq %r13, %rcx
decq %rcx
movq %rcx, %xmm1
pshufd $0x44, %xmm1, %xmm1     # xmm1 = xmm1[0,1,0,1]
shrl %eax
shlq $0x4, %rax
pmovsxbq 0x639a(%rip), %xmm2     # 0xd4e0
xorl %ecx, %ecx
movdqa 0x5f60(%rip), %xmm3     # 0xd0b0
pxor %xmm3, %xmm1
pcmpeqd %xmm4, %xmm4
pmovsxbq 0x6381(%rip), %xmm5     # 0xd4e2
movdqa %xmm2, %xmm6
pxor %xmm3, %xmm6
pcmpgtq %xmm1, %xmm6
movd %xmm6, %edx
notl %edx
testb $0x1, %dl
je 0x717f
movsd %xmm0, (%r12,%rcx)
pxor %xmm4, %xmm6
pextrb $0x8, %xmm6, %edx
testb $0x1, %dl
je 0x7195
movsd %xmm0, 0x8(%r12,%rcx)
paddq %xmm5, %xmm2
addq $0x10, %rcx
cmpq %rcx, %rax
jne 0x7161
cmpl $0x1, %r13d
je 0x71fc
movsd 0x48(%r15), %xmm0
xorl %eax, %eax
movl %eax, %ecx
leal 0x1(%rcx), %eax
leal -0x1(%rcx), %esi
imull %ecx, %esi
movl %esi, %edx
shrl $0x1f, %edx
addl %esi, %edx
sarl %edx
movl %eax, %esi
cmpl %esi, %ecx
jae 0x71e1
leal -0x1(%rsi), %r8d
imull %esi, %r8d
movl %r8d, %edi
shrl $0x1f, %edi
addl %r8d, %edi
sarl %edi
addl %ecx, %edi
jmp 0x71e4
leal (%rdx,%rsi), %edi
addl %r13d, %edi
movslq %edi, %rdi
movsd %xmm0, (%r12,%rdi,8)
incl %esi
cmpl %esi, %r13d
jne 0x71c6
cmpl %r14d, %eax
jne 0x71b0
cmpl $0x1, 0x18(%r15)
movq %r12, 0x10(%rsp)
jne 0x725b
movq 0x10(%rbx), %rdi
callq 0x10c0
decl %eax
movl %eax, 0x8(%rbx)
testl %r13d, %r13d
jle 0x725b
movl (%rbx), %ecx
xorl %eax, %eax
testl %ecx, %ecx
jle 0x7243
movq 0x20(%rbx), %rdx
xorl %esi, %esi
movl 0x4(%rbx), %ecx
imull %esi, %ecx
addl %eax, %ecx
movslq %ecx, %rcx
decl (%rdx,%rcx,4)
incl %esi
movl (%rbx), %ecx
cmpl %ecx, %esi
jl 0x7229
movl 0x4(%rbx), %r13d
incl %eax
cmpl %r13d, %eax
jl 0x721f
leal -0x1(%r13), %eax
imull %r13d, %eax
movl %eax, %ebp
shrl $0x1f, %ebp
addl %eax, %ebp
sarl %ebp
movl 0x8(%rbx), %r14d
imull %r14d, %ebp
addl %r13d, %ebp
imull %r14d, %ebp
movl %ebp, 0x68(%rbx)
movslq %ebp, %rdi
shlq $0x3, %rdi
callq 0x11b0
testq %rax, %rax
je 0x73e7
movq %rax, %r12
testl %ebp, %ebp
jle 0x7299
movl %ebp, %edx
shlq $0x3, %rdx
movq %r12, %rdi
xorl %esi, %esi
callq 0x1110
cmpl $0x1, 0x58(%r15)
je 0x7387
testl %r13d, %r13d
jle 0x7387
movq %r15, 0x8(%rsp)
xorl %ebp, %ebp
movsd 0x5dac(%rip), %xmm1     # 0xd068
testl %r14d, %r14d
jle 0x730e
xorl %r15d, %r15d
movq 0x58(%rbx), %rax
imull %r15d, %r13d
addl %ebp, %r13d
movslq %r13d, %rcx
movsd (%rax,%rcx,8), %xmm0
mulsd 0x48(%rbx), %xmm0
addsd %xmm1, %xmm0
callq 0x1130
movsd 0x5d7b(%rip), %xmm1     # 0xd068
movl 0x4(%rbx), %r13d
movl %r13d, %eax
imull %r15d, %eax
addl %ebp, %eax
cltq
movsd %xmm0, (%r12,%rax,8)
incl %r15d
movl 0x8(%rbx), %r14d
cmpl %r14d, %r15d
jl 0x72c4
incl %ebp
cmpl %r13d, %ebp
jl 0x72bc
testl %r13d, %r13d
movq 0x8(%rsp), %r15
jle 0x7387
xorps %xmm0, %xmm0
cvtsi2sd %r14d, %xmm0
movl %r13d, %eax
movl %r14d, %ecx
leaq (,%rax,8), %rdx
xorl %esi, %esi
movq %r12, %rdi
testl %r14d, %r14d
jle 0x737b
xorpd %xmm1, %xmm1
movq %rcx, %r8
movq %rdi, %r9
addsd (%r9), %xmm1
addq %rdx, %r9
decq %r8
jne 0x7349
testl %r14d, %r14d
jle 0x737b
divsd %xmm0, %xmm1
movq %rcx, %r8
movq %rdi, %r9
movsd (%r9), %xmm2
subsd %xmm1, %xmm2
movsd %xmm2, (%r9)
addq %rdx, %r9
decq %r8
jne 0x7365
incq %rsi
addq $0x8, %rdi
cmpq %rax, %rsi
jne 0x733a
movq %r12, %rdi
movq 0x10(%rsp), %rsi
movq %rbx, %rdx
movq %r15, %rcx
callq 0x73ec
cmpl $0x1, 0x18(%r15)
jne 0x73d5
movl 0x4(%rbx), %edx
testl %edx, %edx
jle 0x73d5
movl (%rbx), %ecx
xorl %eax, %eax
testl %ecx, %ecx
jle 0x73cf
movq 0x20(%rbx), %rdx
xorl %esi, %esi
movl 0x4(%rbx), %ecx
imull %esi, %ecx
addl %eax, %ecx
movslq %ecx, %rcx
incl (%rdx,%rcx,4)
incl %esi
movl (%rbx), %ecx
cmpl %ecx, %esi
jl 0x73b6
movl 0x4(%rbx), %edx
incl %eax
cmpl %edx, %eax
jl 0x73ac
movq %r12, %rax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
callq 0x2208