// File: /workspace/github_c_makefile_star2_O3/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 0xf310
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 0xf2ea
subsd %xmm2, %xmm3
movsd %xmm3, (%rax,%rcx,8)
incl %ebp
cmpl %r12d, %ebp
jbe 0xf2a9
movl %r12d, %ebp
movl $0x1, %eax
cmpl $0x2, %ebp
jae 0xf340
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x1cd07(%rip), %rax     # 0x2bff8
movq (%rax), %rdi
leaq 0x13602(%rip), %rsi     # 0x228fd
leaq 0x135ea(%rip), %rdx     # 0x228ec
movl %ebp, %ecx
movl %r12d, %r8d
movb $0x1, %al
callq 0x22c0
jmp 0xf2d1
movsd 0x8(%r15), %xmm0
movq 0x1ccdb(%rip), %rax     # 0x2bff8
movq (%rax), %rdi
leaq 0x135a5(%rip), %rsi     # 0x228cc
leaq 0x135be(%rip), %rdx     # 0x228ec
movsd %xmm0, 0x10(%rsp)
movb $0x1, %al
callq 0x22c0
jmp 0xf27f
movl (%r15), %eax
xorpd %xmm0, %xmm0
movsd %xmm0, 0x8(%rsp)
movsd %xmm0, (%rsp)
movq %rax, 0x38(%rsp)
testq %rax, %rax
je 0xf5a1
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 0xf588
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), %r10
movsd 0x13289(%rip), %xmm6    # 0x22660
xorpd %xmm5, %xmm5
movsd 0x10(%rsp), %xmm4
movq %rax, %r11
xorl %ecx, %ecx
movq 0x20(%rsp), %r8
movl %ecx, %eax
xorl %edx, %edx
divl %r12d
addl %eax, %edx
cmpl %r13d, %edx
jae 0xf46c
movl %edx, %eax
movsd 0x8(%r8,%rax,8), %xmm0
ucomisd %xmm5, %xmm0
jbe 0xf46c
movq 0x20(%r10), %rsi
movsd (%rsi,%rcx,8), %xmm1
ucomisd %xmm1, %xmm5
ja 0xf46c
movapd %xmm1, %xmm2
xorl %esi, %esi
subsd %xmm4, %xmm2
xorpd %xmm3, %xmm3
maxsd %xmm2, %xmm3
divsd %xmm0, %xmm3
movapd %xmm6, %xmm2
minsd %xmm3, %xmm2
movl %r13d, %edi
imull %esi, %edi
addl %edx, %edi
addsd (%r15,%rdi,8), %xmm2
movsd %xmm2, (%r15,%rdi,8)
cmpq $0x3, %rsi
je 0xf468
movq (%rbp,%rsi,8), %rdi
movsd (%rdi,%rcx,8), %xmm2
incq %rsi
ucomisd %xmm2, %xmm5
jbe 0xf41d
ucomisd %xmm1, %xmm5
ja 0xf46c
incl (%r11,%rax,4)
incq %rcx
cmpq %r14, %rcx
jne 0xf3eb
movl (%r11), %eax
testl %eax, %eax
je 0xf56b
xorl %ecx, %ecx
xorl %edx, %edx
movl %ecx, %esi
movsd (%r15,%rsi,8), %xmm0
movsd %xmm0, (%rbx,%rdx,8)
incq %rdx
addl %r13d, %ecx
cmpq $0x4, %rdx
jne 0xf487
cmpl $0x2, %r13d
jb 0xf50c
movl $0x1, %ecx
xorl %edx, %edx
movl %eax, %esi
xorps %xmm0, %xmm0
cvtsi2sd %rsi, %xmm0
movl %edx, %esi
xorl %edi, %edi
leal 0x1(%rsi), %r8d
movsd (%r15,%r8,8), %xmm1
movl %esi, %r9d
movsd (%r15,%r9,8), %xmm2
movapd %xmm1, %xmm3
mulsd %xmm2, %xmm3
divsd %xmm0, %xmm3
addsd (%rbx,%rdi,8), %xmm3
movsd %xmm3, (%rbx,%rdi,8)
addsd %xmm2, %xmm1
movsd %xmm1, (%r15,%r8,8)
incq %rdi
addl %r13d, %esi
cmpq $0x4, %rdi
jne 0xf4bb
addl (%r11,%rcx,4), %eax
movl %eax, (%r11,%rcx,4)
incq %rcx
incl %edx
cmpq %r13, %rcx
jne 0xf4ad
decl %r13d
movl (%r11,%r13,4), %eax
xorps %xmm0, %xmm0
cvtsi2sd %rax, %xmm0
xorpd %xmm1, %xmm1
xorl %ecx, %ecx
movapd %xmm1, %xmm2
movsd (%rbx,%rcx,8), %xmm3
movapd %xmm3, %xmm1
maxsd %xmm2, %xmm1
divsd %xmm0, %xmm3
movsd %xmm3, (%rbx,%rcx,8)
incq %rcx
cmpq $0x4, %rcx
jne 0xf521
movq %r11, %r14
movl %eax, 0x18(%r10)
movsd 0x8(%rsp), %xmm2
addsd %xmm0, %xmm2
movsd %xmm2, 0x8(%rsp)
movsd (%rsp), %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, (%rsp)
jmp 0xf56e
movq %r11, %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 0xf37e
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 0x1ca27(%rip), %rax     # 0x2bff8
movq (%rax), %rdi
leaq 0x1336a(%rip), %rsi     # 0x22945
leaq 0x1330a(%rip), %rdx     # 0x228ec
movb $0x3, %al
callq 0x22c0
movq 0x20(%rsp), %rdi
callq 0x2060
xorl %eax, %eax
jmp 0xf2db