// File: /workspace/github_c_makefile_star2_O2/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, %r14
movq %rdi, %rbx
movl 0x4(%rdi), %ebp
leal -0x1(%rbp), %r13d
movl %r13d, %eax
imull %ebp, %eax
pushq $0x2
popq %r12
cltd
idivl %r12d
movq %rax, 0x8(%rsp)
addl %ebp, %eax
movslq %eax, %rdi
shlq $0x3, %rdi
callq 0x11a0
movq %rax, %r15
xorl %eax, %eax
testl %ebp, %ebp
movl $0x0, %ecx
cmovgl %ebp, %ecx
cmpq %rax, %rcx
je 0x58d1
movsd 0x40(%r14), %xmm0
movsd %xmm0, (%r15,%rax,8)
incq %rax
jmp 0x58bb
xorl %ecx, %ecx
testl %r13d, %r13d
cmovlel %ecx, %r13d
cmpl %r13d, %ecx
je 0x590c
leal 0x1(%rcx), %esi
addl %ebp, %ecx
movl %esi, %edi
cmpl %edi, %ebp
je 0x5908
movsd 0x48(%r14), %xmm0
leal -0x1(%rdi), %eax
imull %edi, %eax
cltd
idivl %r12d
addl %ecx, %eax
cltq
movsd %xmm0, (%r15,%rax,8)
incl %edi
jmp 0x58e6
movl %esi, %ecx
jmp 0x58da
cmpl $0x1, 0x18(%r14)
jne 0x5947
movq 0x10(%rbx), %rdi
callq 0x10c0
decl %eax
movl %eax, 0x8(%rbx)
xorl %eax, %eax
cmpl %ebp, %eax
jge 0x594e
xorl %ecx, %ecx
movl 0x4(%rbx), %ebp
cmpl (%rbx), %ecx
jge 0x5943
movq 0x20(%rbx), %rdx
imull %ecx, %ebp
addl %eax, %ebp
movslq %ebp, %rsi
decl (%rdx,%rsi,4)
incl %ecx
jmp 0x5929
incl %eax
jmp 0x5923
movq 0x8(%rsp), %r12
jmp 0x595b
leal -0x1(%rbp), %eax
imull %ebp, %eax
cltd
idivl %r12d
movl %eax, %r12d
movl 0x8(%rbx), %r13d
imull %r13d, %r12d
addl %ebp, %r12d
imull %r13d, %r12d
movl %r12d, 0x68(%rbx)
movslq %r12d, %rdi
shlq $0x3, %rdi
callq 0x11a0
movq %rax, 0x8(%rsp)
testq %rax, %rax
je 0x5ad6
xorl %eax, %eax
testl %r12d, %r12d
cmovlel %eax, %r12d
movq 0x8(%rsp), %rcx
cmpq %rax, %r12
je 0x59a5
andq $0x0, (%rcx,%rax,8)
incq %rax
jmp 0x5996
cmpl $0x1, 0x58(%r14)
jne 0x5a01
movq 0x8(%rsp), %rdi
movq %r15, %rsi
movq %rbx, %rdx
movq %r14, %rcx
callq 0x5afa
cmpl $0x1, 0x18(%r14)
jne 0x59ed
xorl %eax, %eax
cmpl 0x4(%rbx), %eax
jge 0x59ed
xorl %ecx, %ecx
cmpl (%rbx), %ecx
jge 0x59e9
movq 0x20(%rbx), %rdx
movl 0x4(%rbx), %esi
imull %ecx, %esi
addl %eax, %esi
movslq %esi, %rsi
incl (%rdx,%rsi,4)
incl %ecx
jmp 0x59cf
incl %eax
jmp 0x59c8
movq 0x8(%rsp), %rax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
xorl %r12d, %r12d
movq %r14, 0x10(%rsp)
cmpl %ebp, %r12d
jge 0x5a66
xorl %r14d, %r14d
cmpl %r13d, %r14d
jge 0x5a5c
movq 0x58(%rbx), %rax
imull %r14d, %ebp
addl %r12d, %ebp
movslq %ebp, %rcx
movsd (%rax,%rcx,8), %xmm0
mulsd 0x48(%rbx), %xmm0
addsd 0x6632(%rip), %xmm0     # 0xc068
callq 0x1120
movl 0x4(%rbx), %ebp
movl %ebp, %eax
imull %r14d, %eax
addl %r12d, %eax
cltq
movq 0x8(%rsp), %rcx
movsd %xmm0, (%rcx,%rax,8)
incl %r14d
movl 0x8(%rbx), %r13d
jmp 0x5a11
incl %r12d
movq 0x10(%rsp), %r14
jmp 0x5a09
movslq %ebp, %rax
xorl %ecx, %ecx
testl %ebp, %ebp
cmovlel %ecx, %ebp
testl %r13d, %r13d
movl $0x0, %edx
cmovgl %r13d, %edx
cvtsi2sd %r13d, %xmm0
shlq $0x3, %rax
movq 0x8(%rsp), %rsi
cmpq %rbp, %rcx
je 0x59ac
xorpd %xmm1, %xmm1
movq %rsi, %rdi
movq %rdx, %r8
subq $0x1, %r8
jb 0x5aac
addsd (%rdi), %xmm1
addq %rax, %rdi
jmp 0x5a9d
divsd %xmm0, %xmm1
movq %rsi, %rdi
movq %rdx, %r8
subq $0x1, %r8
jb 0x5acd
movsd (%rdi), %xmm2
subsd %xmm1, %xmm2
movsd %xmm2, (%rdi)
addq %rax, %rdi
jmp 0x5ab6
incq %rcx
addq $0x8, %rsi
jmp 0x5a8a
movq 0xa51b(%rip), %rax      # 0xfff8
movq (%rax), %rcx
leaq 0x69fd(%rip), %rdi      # 0xc4e4
pushq $0x38
popq %rsi
pushq $0x1
popq %rdx
callq 0x1200
pushq $0x1
popq %rdi
callq 0x11f0