// File: /workspace/github_c_makefile_star2_O2/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 $0x58, %rsp
movq %rcx, 0x40(%rsp)
movsd %xmm0, (%rsp)
movq %rsi, %r12
movq %rdi, %r15
xorps %xmm0, %xmm0
movsd %xmm0, 0x8(%rsp)
testl %edx, %edx
jne 0xb3b3
movl 0x4(%r15), %ebx
leal 0x1(%rbx), %edi
pushq $0x8
popq %rsi
callq 0x2290
movq 0x10(%r12), %rdx
xorl %ebp, %ebp
movsd 0x8(%rsp), %xmm2
movq %rax, 0x28(%rsp)
movsd (%rsp), %xmm0
cmpl %ebx, %ebp
ja 0xb39a
movl %ebp, %ecx
movsd (%rdx,%rcx,8), %xmm3
movapd %xmm3, %xmm1
mulsd %xmm0, %xmm1
ucomisd %xmm2, %xmm1
jbe 0xb6b5
subsd %xmm2, %xmm3
movsd %xmm3, (%rax,%rcx,8)
incl %ebp
jmp 0xb370
movl %ebx, %ebp
cmpl $0x2, %ebp
jae 0xb3e3
pushq $0x1
popq %rax
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movsd 0x8(%r15), %xmm0
movq 0x1cc38(%rip), %rax     # 0x27ff8
movq (%rax), %rdi
leaq 0x134ba(%rip), %rsi     # 0x1e884
leaq 0x134d3(%rip), %rdx     # 0x1e8a4
movsd %xmm0, 0x8(%rsp)
movb $0x1, %al
callq 0x22c0
jmp 0xb34a
movl (%r15), %eax
movq %rax, 0x48(%rsp)
pushq $0x20
popq %rax
pushq $0x60
popq %r13
xorl %r12d, %r12d
xorpd %xmm0, %xmm0
movsd %xmm0, 0x18(%rsp)
movsd %xmm0, 0x10(%rsp)
movq %r15, 0x20(%rsp)
cmpq 0x48(%rsp), %r12
je 0xb65b
movq %r13, (%rsp)
movq 0x10(%r15), %r14
movq %r12, %rcx
shlq $0x7, %rcx
movl 0x14(%r14,%rcx), %r13d
testq %r13, %r13
je 0xb61f
movq %r12, 0x30(%rsp)
addq %r14, %rcx
movl 0xc(%rcx), %r15d
movq %rcx, 0x50(%rsp)
movl 0x10(%rcx), %r12d
leal (,%r12,4), %edi
pushq $0x8
popq %rsi
movq %rax, 0x38(%rsp)
callq 0x2290
movq %rax, %rbp
movq %r12, %rdi
pushq $0x4
popq %rsi
callq 0x2290
movsd 0x131a6(%rip), %xmm5    # 0x1e618
xorpd %xmm4, %xmm4
movsd 0x8(%rsp), %xmm3
movq %rax, %rbx
movq 0x38(%rsp), %rax
leaq (%r14,%rax), %rsi
xorl %ecx, %ecx
movq 0x28(%rsp), %r10
cmpq %r13, %rcx
je 0xb519
movl %ecx, %eax
xorl %edx, %edx
divl %r15d
addl %eax, %edx
cmpl %r12d, %edx
jae 0xb511
movl %edx, %eax
movsd 0x8(%r10,%rax,8), %xmm0
ucomisd %xmm4, %xmm0
jbe 0xb511
movb $0x1, %r8b
xorl %edi, %edi
cmpq $0x4, %rdi
je 0xb508
movq (%rsi,%rdi,8), %r9
movsd (%r9,%rcx,8), %xmm1
ucomisd %xmm1, %xmm4
ja 0xb508
subsd %xmm3, %xmm1
xorpd %xmm2, %xmm2
maxsd %xmm1, %xmm2
divsd %xmm0, %xmm2
movapd %xmm5, %xmm1
minsd %xmm2, %xmm1
movl %edi, %r8d
imull %r12d, %r8d
addl %edx, %r8d
addsd (%rbp,%r8,8), %xmm1
movsd %xmm1, (%rbp,%r8,8)
incq %rdi
xorl %r8d, %r8d
jmp 0xb4ba
testb $0x1, %r8b
jne 0xb511
incl (%rbx,%rax,4)
incq %rcx
jmp 0xb48f
movl (%rbx), %eax
testl %eax, %eax
je 0xb625
movq (%rsp), %r13
addq %r13, %r14
xorl %ecx, %ecx
xorl %edx, %edx
movq 0x20(%rsp), %r15
cmpq $0x4, %rdx
je 0xb54f
movl %ecx, %esi
movsd (%rbp,%rsi,8), %xmm0
movsd %xmm0, (%r14,%rdx,8)
incq %rdx
addl %r12d, %ecx
jmp 0xb533
xorl %ecx, %ecx
pushq $0x1
popq %rdx
cmpq %r12, %rdx
jae 0xb5b7
movl %eax, %esi
cvtsi2sd %rsi, %xmm0
movl %ecx, %esi
xorl %edi, %edi
cmpq $0x4, %rdi
je 0xb5aa
leal 0x1(%rsi), %r8d
movsd (%rbp,%r8,8), %xmm1
movl %esi, %r9d
movsd (%rbp,%r9,8), %xmm2
movapd %xmm1, %xmm3
mulsd %xmm2, %xmm3
divsd %xmm0, %xmm3
addsd (%r14,%rdi,8), %xmm3
movsd %xmm3, (%r14,%rdi,8)
addsd %xmm2, %xmm1
movsd %xmm1, (%rbp,%r8,8)
incq %rdi
addl %r12d, %esi
jmp 0xb564
addl (%rbx,%rdx,4), %eax
movl %eax, (%rbx,%rdx,4)
incq %rdx
incl %ecx
jmp 0xb554
decl %r12d
movl (%rbx,%r12,4), %eax
cvtsi2sd %rax, %xmm0
xorpd %xmm1, %xmm1
xorl %ecx, %ecx
movq 0x30(%rsp), %r12
cmpq $0x4, %rcx
je 0xb5f5
movsd (%r14,%rcx,8), %xmm2
movapd %xmm2, %xmm3
maxsd %xmm1, %xmm3
divsd %xmm0, %xmm2
movsd %xmm2, (%r14,%rcx,8)
incq %rcx
movapd %xmm3, %xmm1
jmp 0xb5ce
movq 0x50(%rsp), %rcx
movl %eax, 0x18(%rcx)
movsd 0x18(%rsp), %xmm2
addsd %xmm0, %xmm2
movsd %xmm2, 0x18(%rsp)
movsd 0x10(%rsp), %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x10(%rsp)
jmp 0xb633
movq (%rsp), %r13
jmp 0xb648
movq 0x20(%rsp), %r15
movq (%rsp), %r13
movq 0x30(%rsp), %r12
movq %rbp, %rdi
callq 0x2060
movq %rbx, %rdi
callq 0x2060
movq 0x38(%rsp), %rax
incq %r12
movl $0x80, %ecx
addq %rcx, %rax
addq %rcx, %r13
jmp 0xb40a
movsd 0x10(%rsp), %xmm0
movapd %xmm0, %xmm3
movsd 0x18(%rsp), %xmm1
divsd %xmm1, %xmm3
xorpd %xmm2, %xmm2
cmpeqsd %xmm1, %xmm2
andnpd %xmm3, %xmm2
movq 0x40(%rsp), %rax
movlpd %xmm2, (%rax)
movq 0x1c96c(%rip), %rax     # 0x27ff8
movq (%rax), %rdi
leaq 0x13267(%rip), %rsi     # 0x1e8fd
leaq 0x13207(%rip), %rdx     # 0x1e8a4
movb $0x3, %al
callq 0x22c0
movq 0x28(%rsp), %rdi
callq 0x2060
xorl %eax, %eax
jmp 0xb3a4
movq 0x1c93c(%rip), %rax     # 0x27ff8
movq (%rax), %rdi
leaq 0x131ef(%rip), %rsi     # 0x1e8b5
leaq 0x131d7(%rip), %rdx     # 0x1e8a4
movl %ebp, %ecx
movl %ebx, %r8d
movb $0x1, %al
callq 0x22c0
jmp 0xb39c