// File: /workspace/github_c_makefile_star2_O1/c-zhou[P]yahs/link.c
// Function: inter_link_norms
int inter_link_norms(inter_link_mat_t *link_mat, norm_t *norm, int use_estimated_noise, double max_noise_ratio, double *la)
{
    uint32_t i, j, k, b, b1, r, n, n0;
    uint32_t *fn;
    int8_t bl;
    double l, *norms, *fr, noise;
    double c, c0, t;
    inter_link_t *inter_link;

    noise = .0;
    if (use_estimated_noise) {
        // noise = estimate_noise(link_mat);
        noise = link_mat->noise;
        fprintf(stderr, "[I::%s] using noise level %.3f\n", __func__, noise);
    }

    r = link_mat->r;
    norms = (double *) calloc(r + 1, sizeof(double));
    for (i = 0; i <= r; ++i) {
        if (norm->norms[i] * max_noise_ratio > noise) {
            norms[i] = norm->norms[i] - noise;
        } else {
            fprintf(stderr, "[I::%s] using new radius %u (%u) as noise ratio exceeds threshold %.3f\n", __func__, i, r, max_noise_ratio);
            r = i;
            break;
        }
    }
    if (r <= 1) return 1;

    /***
    // no weighting
    c = c0 = 0;
    for (i = 0; i < link_mat->n; ++i) {
        inter_link = &link_mat->links[i];
        n = inter_link->n;
        if (n == 0)
            continue;
        r = inter_link->r;
        b1 = inter_link->b1;
        n0 = 0;
        for (j = 0; j < n; ++j) {
            b = j / b1 + j % b1;
            if (b < r) {
                if (norms[b + 1] > 0) {
                    bl = 0;
                    for (k = 0; k < 4; ++k) {
                        l = inter_link->link[k][j];
                        if (l < .0)
                            break;
                        if (l >= norms[b + 1] + noise) {
                            inter_link->norms[k] += 1.;
                            ++c0;
                        }
                        bl = 1;
                    }
                    if (bl)
                        ++n0;
                }
            }
        }
        for (k = 0; k < 4; ++k)
            inter_link->norms[k] /= n0;
        inter_link->n0 = n0;
        c += n0;
    }
    **/
    
    c = c0 = 0;
    for (i = 0; i < link_mat->n; ++i) {
        inter_link = &link_mat->links[i];
        n = inter_link->n;
        if (n == 0)
            continue;
        r = inter_link->r;
        b1 = inter_link->b1;

        fr = (double *) calloc(4 * r, sizeof(double));
        fn = (uint32_t *) calloc(r, sizeof(uint32_t));

        for (j = 0; j < n; ++j) {
            b = j / b1 + j % b1;
            if (b < r) {
                if (norms[b + 1] > 0) {
                    bl = 0;
                    for (k = 0; k < 4; ++k) {
                        l = inter_link->link[k][j];
                        if(l < .0)
                            break;
                        l = MAX(.0, l - noise);
                        fr[k * r + b] += MIN(1., l / norms[b + 1]);
                        bl = 1;
                    }
                    if (bl)
                        ++fn[b];
                }
            }
        }
        if (fn[0] == 0)
            goto loop_i_end;

        // cumsum
        for (k = 0; k < 4; ++k)
            inter_link->norms[k] = fr[k * r];
        for (b = 1; b < r; ++b) {
            for (k = 0; k < 4; ++k) {
                inter_link->norms[k] += fr[k * r + b] * fr[k * r + b - 1] / fn[b - 1];
                fr[k * r + b] += fr[k * r + b - 1];
            }
            fn[b] += fn[b - 1];
        }

        n0 = fn[r - 1];
        t = 0;
        for (k = 0; k < 4; ++k) {
            if (inter_link->norms[k] > t)
                t = inter_link->norms[k];
            inter_link->norms[k] /= n0;
        }
        inter_link->n0 = n0;
        c += n0;
        c0 += t;
loop_i_end:
        free(fr);
        free(fn);
    }
    
    *la = c == 0? .0 : c0 / c;
    fprintf(stderr, "[I::%s] average link count: %.3f %.3f %.3f\n", __func__, c0, c, *la);
    
    free(norms);

    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movq %rcx, 0x28(%rsp)
movsd %xmm0, 0x18(%rsp)
movq %rsi, %r13
movq %rdi, %r15
xorps %xmm0, %xmm0
movsd %xmm0, 0x10(%rsp)
testl %edx, %edx
jne 0xe4ed
movl 0x4(%r15), %r12d
leal 0x1(%r12), %edi
movl $0x8, %esi
callq 0x2290
movq 0x10(%r13), %rdx
xorl %ebp, %ebp
movsd 0x10(%rsp), %xmm2
movq %rax, 0x20(%rsp)
movsd 0x18(%rsp), %xmm0
movl %ebp, %ecx
movsd (%rdx,%rcx,8), %xmm3
movapd %xmm3, %xmm1
mulsd %xmm0, %xmm1
ucomisd %xmm2, %xmm1
jbe 0xe4c7
subsd %xmm2, %xmm3
movsd %xmm3, (%rax,%rcx,8)
incl %ebp
cmpl %r12d, %ebp
jbe 0xe486
movl %r12d, %ebp
movl $0x1, %eax
cmpl $0x2, %ebp
jae 0xe51d
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x1cb2a(%rip), %rax     # 0x2aff8
movq (%rax), %rdi
leaq 0x133ed(%rip), %rsi     # 0x218c5
leaq 0x133d5(%rip), %rdx     # 0x218b4
movl %ebp, %ecx
movl %r12d, %r8d
movb $0x1, %al
callq 0x22c0
jmp 0xe4ae
movsd 0x8(%r15), %xmm0
movq 0x1cafe(%rip), %rax     # 0x2aff8
movq (%rax), %rdi
leaq 0x13390(%rip), %rsi     # 0x21894
leaq 0x133a9(%rip), %rdx     # 0x218b4
movsd %xmm0, 0x10(%rsp)
movb $0x1, %al
callq 0x22c0
jmp 0xe45c
movl (%r15), %eax
xorpd %xmm0, %xmm0
movsd %xmm0, 0x8(%rsp)
movsd %xmm0, (%rsp)
movq %rax, 0x38(%rsp)
testq %rax, %rax
je 0xe78b
movq 0x10(%r15), %rax
leaq 0x28(%rax), %rbp
leaq 0x60(%rax), %rbx
xorl %ecx, %ecx
movsd %xmm0, (%rsp)
movsd %xmm0, 0x8(%rsp)
movq %rax, 0x30(%rsp)
movq %rcx, %rdx
shlq $0x7, %rdx
movl 0x14(%rax,%rdx), %r14d
testq %r14, %r14
je 0xe772
movq %rcx, 0x18(%rsp)
addq %rax, %rdx
movq %rdx, 0x40(%rsp)
movl 0xc(%rdx), %r12d
movl 0x10(%rdx), %r13d
leal (,%r13,4), %edi
movl $0x8, %esi
callq 0x2290
movq %rax, %r15
movl $0x4, %esi
movq %r13, %rdi
callq 0x2290
movq 0x40(%rsp), %r9
movsd 0x1307c(%rip), %xmm6    # 0x21630
xorpd %xmm5, %xmm5
movsd 0x10(%rsp), %xmm4
movq %rax, %r10
xorl %ecx, %ecx
movq 0x20(%rsp), %rdi
movl %ecx, %eax
xorl %edx, %edx
divl %r12d
addl %eax, %edx
cmpl %r13d, %edx
jae 0xe64a
leal 0x1(%rdx), %eax
movsd (%rdi,%rax,8), %xmm0
ucomisd %xmm5, %xmm0
jbe 0xe64a
movq 0x20(%r9), %rax
movsd (%rax,%rcx,8), %xmm1
ucomisd %xmm1, %xmm5
ja 0xe64a
movapd %xmm1, %xmm2
xorl %eax, %eax
subsd %xmm4, %xmm2
xorpd %xmm3, %xmm3
maxsd %xmm2, %xmm3
divsd %xmm0, %xmm3
movapd %xmm6, %xmm2
minsd %xmm3, %xmm2
movl %r13d, %esi
imull %eax, %esi
addl %edx, %esi
addsd (%r15,%rsi,8), %xmm2
movsd %xmm2, (%r15,%rsi,8)
cmpq $0x3, %rax
je 0xe644
movq (%rbp,%rax,8), %rsi
movsd (%rsi,%rcx,8), %xmm2
incq %rax
ucomisd %xmm2, %xmm5
jbe 0xe5f9
ucomisd %xmm1, %xmm5
ja 0xe64a
movl %edx, %eax
incl (%r10,%rax,4)
incq %rcx
cmpq %r14, %rcx
jne 0xe5c8
cmpl $0x0, (%r10)
je 0xe755
xorl %eax, %eax
xorl %ecx, %ecx
movl %eax, %edx
movsd (%r15,%rdx,8), %xmm0
movsd %xmm0, (%rbx,%rcx,8)
incq %rcx
addl %r13d, %eax
cmpq $0x4, %rcx
jne 0xe664
cmpl $0x2, %r13d
jb 0xe6ec
movl $0x1, %eax
xorl %ecx, %ecx
movl -0x4(%r10,%rax,4), %edx
xorps %xmm0, %xmm0
cvtsi2sd %rdx, %xmm0
movl %ecx, %edx
xorl %esi, %esi
leal 0x1(%rdx), %edi
movsd (%r15,%rdi,8), %xmm1
movl %edx, %r8d
movsd (%r15,%r8,8), %xmm2
movapd %xmm1, %xmm3
mulsd %xmm2, %xmm3
divsd %xmm0, %xmm3
addsd (%rbx,%rsi,8), %xmm3
movsd %xmm3, (%rbx,%rsi,8)
addsd %xmm2, %xmm1
movsd %xmm1, (%r15,%rdi,8)
incq %rsi
addl %r13d, %edx
cmpq $0x4, %rsi
jne 0xe69b
movl -0x4(%r10,%rax,4), %edx
addl %edx, (%r10,%rax,4)
incq %rax
incl %ecx
cmpq %r13, %rax
jne 0xe68a
decl %r13d
movl (%r10,%r13,4), %eax
xorps %xmm1, %xmm1
cvtsi2sd %rax, %xmm1
xorpd %xmm0, %xmm0
xorl %ecx, %ecx
movapd %xmm0, %xmm2
movsd (%rbx,%rcx,8), %xmm3
movapd %xmm3, %xmm0
maxsd %xmm2, %xmm0
divsd %xmm1, %xmm3
movsd %xmm3, (%rbx,%rcx,8)
incq %rcx
cmpq $0x4, %rcx
jne 0xe701
movq %r10, %r14
movl %eax, 0x18(%r9)
movl %eax, %eax
xorps %xmm1, %xmm1
cvtsi2sd %rax, %xmm1
movsd 0x8(%rsp), %xmm2
addsd %xmm1, %xmm2
movsd %xmm2, 0x8(%rsp)
movsd (%rsp), %xmm1
addsd %xmm0, %xmm1
movsd %xmm1, (%rsp)
jmp 0xe758
movq %r10, %r14
movq %r15, %rdi
callq 0x2060
movq %r14, %rdi
callq 0x2060
movq 0x30(%rsp), %rax
movq 0x18(%rsp), %rcx
incq %rcx
movl $0x80, %edx
addq %rdx, %rbp
addq %rdx, %rbx
cmpq 0x38(%rsp), %rcx
jne 0xe55b
movsd (%rsp), %xmm0
movapd %xmm0, %xmm3
movsd 0x8(%rsp), %xmm1
divsd %xmm1, %xmm3
xorpd %xmm2, %xmm2
cmpeqsd %xmm1, %xmm2
andnpd %xmm3, %xmm2
movq 0x28(%rsp), %rax
movlpd %xmm2, (%rax)
movq 0x1c83d(%rip), %rax     # 0x2aff8
movq (%rax), %rdi
leaq 0x13148(%rip), %rsi     # 0x2190d
leaq 0x130e8(%rip), %rdx     # 0x218b4
movb $0x3, %al
callq 0x22c0
movq 0x20(%rsp), %rdi
callq 0x2060
xorl %eax, %eax
jmp 0xe4b8