// File: /workspace/github_c_makefile_star2_O2/c-zhou[P]yahs/yahs.c
// Function: run_scaffolding
int run_scaffolding(char *fai, char *agp, char *link_file, cov_norm_t *cov_norm, uint32_t ml, uint8_t mq, re_cuts_t *re_cuts, int8_t *telo_ends, char *out, int resolution, double *noise, uint32_t d_min_cell, double d_mass_frac, long rss_limit, int no_mem_check)
{
    //TODO: adjust wt thres by resolution
    sdict_t *sdict = make_sdict_from_index(fai, ml);
    asm_dict_t *dict = agp? make_asm_dict_from_agp(sdict, agp, 1) : make_asm_dict_from_sdict(sdict);
    
    int i, re = 0;
    uint64_t len = 0;
    for (i = 0; i < dict->n; ++i)
        len += dict->s[i].len;
#ifdef DEBUG_GRAPH_PRUNE
    fprintf(stderr, "[DEBUG_GRAPH_PRUNE::%s] #sequences loaded %d = %lubp\n", __func__, dict->n, len);
#endif

    long rss_intra, rss_inter;

    rss_intra = no_mem_check? 0 : estimate_intra_link_mat_init_rss(dict, resolution, 1);
    if ((rss_limit >= 0 && rss_intra > rss_limit) || rss_intra < 0) {
        // no enough memory
        fprintf(stderr, "[I::%s] No enough memory. Try lower resolutions... End of scaffolding round.\n", __func__);
        fprintf(stderr, "[I::%s] RAM    limit: %.3fGB\n", __func__, (double) rss_limit / GB);
        fprintf(stderr, "[I::%s] RAM required: %.3fGB\n", __func__, (double) rss_intra / GB);
        re = ENOMEM_ERR;
        goto scaff_failed_0;
    }
    rss_limit -= rss_intra;
    fprintf(stderr, "[I::%s] starting norm estimation...\n", __func__);
    intra_link_mat_t *intra_link_mat = intra_link_mat_from_file(link_file, cov_norm, dict, re_cuts, resolution, 1, mq);

#ifdef DEBUG_RAM_USAGE
    fprintf(stderr, "[DEBUG_RAM_USAGE::%s] RAM  peak: %.3fGB\n", __func__, (double) peakrss() / GB);
    fprintf(stderr, "[DEBUG_RAM_USAGE::%s] RAM intra: %.3fGB\n", __func__, (double) rss_intra / GB);
    fprintf(stderr, "[DEBUG_RAM_USAGE::%s] RAM  free: %.3fGB\n", __func__, (double) rss_limit / GB);
#endif

    norm_t *norm = calc_norms(intra_link_mat, d_min_cell, d_mass_frac);
    if (norm == 0) {
        fprintf(stderr, "[W::%s] No enough bands for norm calculation... End of scaffolding round.\n", __func__);
        re = ENOBND_ERR;
        goto scaff_failed_1;
    }

    rss_inter = no_mem_check? 0 : estimate_inter_link_mat_init_rss(dict, resolution, norm->r);
    if ((rss_limit >= 0 && rss_inter > rss_limit) || rss_inter < 0) {
        // no enough memory
        fprintf(stderr, "[I::%s] No enough memory. Try lower resolutions... End of scaffolding round.\n", __func__);
        fprintf(stderr, "[I::%s] RAM    limit: %.3fGB\n", __func__, (double) rss_limit / GB);
        fprintf(stderr, "[I::%s] RAM required: %.3fGB\n", __func__, (double) rss_inter / GB);
        re = ENOMEM_ERR;
        goto scaff_failed_1;
    }
    rss_limit -= rss_inter;
    fprintf(stderr, "[I::%s] starting link estimation...\n", __func__);
    inter_link_mat_t *inter_link_mat = inter_link_mat_from_file(link_file, cov_norm, dict, re_cuts, resolution, norm->r, mq);

#ifdef DEBUG_RAM_USAGE
    fprintf(stderr, "[DEBUG_RAM_USAGE::%s] RAM  peak: %.3fGB\n", __func__, (double) peakrss() / GB);
    fprintf(stderr, "[DEBUG_RAM_USAGE::%s] RAM inter: %.3fGB\n", __func__, (double) rss_inter / GB);
    fprintf(stderr, "[DEBUG_RAM_USAGE::%s] RAM  free: %.3fGB\n", __func__, (double) rss_limit / GB);
#endif

    *noise = inter_link_mat->noise / resolution / resolution;

    double la;
    re = inter_link_norms(inter_link_mat, norm, 1, max_noise_ratio, &la);
    if (re) {
        goto scaff_failed_2;
    }

    int8_t *directs = 0;
    // directs = calc_link_directs_from_file(link_file, dict);
    calc_link_directs(inter_link_mat, .1, dict, directs);
    if(directs) free(directs);

#ifdef DEBUG_LINK
    fprintf(stderr, "[DEBUG_LINK::%s] print_inter_link_norms\n", __func__);
    print_inter_link_norms(stderr, inter_link_mat, dict);
#endif

    int8_t *telos;
    telos = find_aseq_telos(dict, telo_ends);
    fprintf(stderr, "[I::%s] starting scaffolding graph contruction...\n", __func__);
    graph_t *g = build_graph_from_links(inter_link_mat, dict, .1, la, telos);
    
    free(telos);

#ifdef DEBUG_GRAPH_PRUNE
    fprintf(stderr, "[DEBUG_GRAPH_PRUNE::%s] scaffolding graph (before pruning) in GV format\n", __func__);
    graph_print_gv(g, stderr);
    fprintf(stderr, "[DEBUG_GRAPH_PRUNE::%s] scaffolding graph (before pruning) in GFA format\n", __func__);
    graph_print(g, stderr, 1);
#endif

    uint64_t n_arc;
    n_arc = g->n_arc;
#ifdef DEBUG_GRAPH_PRUNE
    fprintf(stderr, "[DEBUG_GRAPH_PRUNE::%s] number edges before trimming: %ld\n", __func__, n_arc);
    int round = 0;
#endif
    while (1) {
        trim_graph_simple_filter(g, .1, .7, .1, 0);
#ifdef DEBUG_GRAPH_PRUNE
        fprintf(stderr, "[DEBUG_GRAPH_PRUNE::%s] number edges after simple trimming round %d: %ld\n", __func__, round, g->n_arc);
        graph_print_gv(g, stderr);
#endif
        trim_graph_tips(g);
        trim_graph_blunts(g);
        trim_graph_repeats(g);
        trim_graph_transitive_edges(g);
        trim_graph_pop_bubbles(g);
        trim_graph_pop_undirected(g);
        trim_graph_weak_edges(g);
        trim_graph_self_loops(g);
#ifdef DEBUG_GRAPH_PRUNE
        fprintf(stderr, "[DEBUG_GRAPH_PRUNE::%s] number edges after trimming round %d: %ld\n", __func__, ++round, g->n_arc);
        graph_print_gv(g, stderr);
#endif
        if (g->n_arc == n_arc)
            break;
        else
            n_arc = g->n_arc;
    }
    trim_graph_ambiguous_edges(g);

#ifdef DEBUG_GRAPH_PRUNE
    fprintf(stderr, "[DEBUG_GRAPH_PRUNE::%s] scaffolding graph (after pruning) in GV format\n", __func__);
    graph_print_gv(g, stderr);
    fprintf(stderr, "[DEBUG_GRAPH_PRUNE::%s] scaffolding graph (after pruning) in GFA format\n", __func__);
    graph_print(g, stderr, 1);
#endif

    asm_dict_t *d = make_asm_dict_from_graph(g, g->sdict);
    // write scaffolds to AGP file
    FILE *agp_out = NULL;
    if (out) {
        char *agp_out_name = (char *) malloc(strlen(out) + 5);
        sprintf(agp_out_name, "%s.agp", out);
        agp_out = fopen(agp_out_name, "w");
        free(agp_out_name);
    } else {
        agp_out = fopen("scaffolds_FINAL.agp", "w");
    }
    if (agp_out == NULL) {
        fprintf(stderr, "[E::%s] fail to open file to write\n", __func__);
        re = 1;
    } else {
        write_asm_dict_to_agp(d, agp_out);
        fclose(agp_out);
    }

    asm_destroy(d);
    graph_destroy(g);

scaff_failed_2:
    inter_link_mat_destroy(inter_link_mat);

scaff_failed_1:
    norm_destroy(norm);
    intra_link_mat_destroy(intra_link_mat);

scaff_failed_0:
    asm_destroy(dict);
    sd_destroy(sdict);

    return re;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movsd %xmm0, 0x30(%rsp)
movl %r9d, %r12d
movq %rcx, 0x20(%rsp)
movq %rdx, 0x18(%rsp)
movq %rsi, %rbx
movl %r8d, %esi
callq 0xeb03
testq %rbx, %rbx
movq %rax, 0x38(%rsp)
jne 0x1a842
movq %rax, %rdi
callq 0xefa5
jmp 0x1a850
pushq $0x1
popq %rdx
movq %rax, %rdi
movq %rbx, %rsi
callq 0xf408
movq %rax, 0x10(%rsp)
movq 0xb0(%rsp), %rbx
movl 0x98(%rsp), %r14d
cmpl $0x0, 0xb8(%rsp)
jne 0x1a895
pushq $0x1
popq %rdx
movq 0x10(%rsp), %rdi
movl %r14d, %esi
callq 0x9a6e
movq %rax, %r15
testq %rbx, %rbx
js 0x1aa0e
cmpq %rbx, %r15
jbe 0x1a898
jmp 0x1aa17
xorl %r15d, %r15d
movq 0x80(%rsp), %rbp
movq 0xd751(%rip), %r13      # 0x27ff8
movq (%r13), %rdi
leaq 0x5ca0(%rip), %rsi      # 0x20552
leaq 0x5c4d(%rip), %rdx      # 0x20506
xorl %eax, %eax
callq 0x22c0
movzbl %r12b, %r12d
movl %r12d, (%rsp)
pushq $0x1
popq %r9
movq 0x18(%rsp), %rdi
movq 0x20(%rsp), %rsi
movq 0x10(%rsp), %rdx
movq %rbp, %rcx
movl %r14d, %r8d
callq 0x9b11
movq %rax, 0x28(%rsp)
movq %rax, %rdi
movl 0xa8(%rsp), %esi
movsd 0x30(%rsp), %xmm0
callq 0xabbc
movq %rax, %r14
testq %rax, %rax
jne 0x1a929
movq (%r13), %rdi
leaq 0x5c64(%rip), %rsi      # 0x20577
leaq 0x5bec(%rip), %rdx      # 0x20506
xorl %eax, %eax
callq 0x22c0
pushq $0xe
popq %rbx
jmp 0x1a9fa
cmpl $0x0, 0xb8(%rsp)
jne 0x1a960
subq %r15, %rbx
movl 0x20(%r14), %edx
movq 0x10(%rsp), %rdi
movl 0x98(%rsp), %esi
callq 0x984f
movq %rax, %r15
testq %rbx, %rbx
js 0x1aaa6
cmpq %rbx, %r15
ja 0x1aaaf
movq 0xa0(%rsp), %rbx
movq 0xd689(%rip), %r15      # 0x27ff8
movq (%r15), %rdi
leaq 0x5c49(%rip), %rsi      # 0x205c2
leaq 0x5b86(%rip), %rdx      # 0x20506
xorl %eax, %eax
callq 0x22c0
movl 0x20(%r14), %r9d
movl %r12d, (%rsp)
movq 0x18(%rsp), %rdi
movq 0x20(%rsp), %rsi
movq 0x10(%rsp), %rdx
movq 0x80(%rsp), %rcx
movl 0x98(%rsp), %ebp
movl %ebp, %r8d
callq 0xa09e
movq %rax, %r13
cvtsi2sd %ebp, %xmm0
movsd 0x8(%rax), %xmm1
divsd %xmm0, %xmm1
divsd %xmm0, %xmm1
movsd %xmm1, (%rbx)
pushq $0x1
popq %rdx
movsd 0x3c48(%rip), %xmm0     # 0x1e620
leaq 0x40(%rsp), %rcx
movq %rax, %rdi
movq %r14, %rsi
callq 0xb31f
movl %eax, %ebx
testl %eax, %eax
je 0x1ab1d
movq %r13, %rdi
callq 0x94b8
movq %r14, %rdi
callq 0xab6c
movq 0x28(%rsp), %rdi
callq 0x946c
jmp 0x1aa81
testq %r15, %r15
jns 0x1a898
movq 0xd5da(%rip), %r12      # 0x27ff8
movq (%r12), %rdi
leaq 0x5a8f(%rip), %rsi      # 0x204b8
leaq 0x5ad6(%rip), %r14      # 0x20506
movq %r14, %rdx
xorl %eax, %eax
callq 0x22c0
movq (%r12), %rdi
cvtsi2sd %rbx, %xmm0
mulsd 0x5945(%rip), %xmm0     # 0x20390
leaq 0x5ac4(%rip), %rsi      # 0x20516
movq %r14, %rdx
movb $0x1, %al
callq 0x22c0
movq (%r12), %rdi
cvtsi2sd %r15, %xmm0
mulsd 0x5923(%rip), %xmm0     # 0x20390
leaq 0x5ac0(%rip), %rsi      # 0x20534
movq %r14, %rdx
movb $0x1, %al
callq 0x22c0
pushq $0xf
popq %rbx
movq 0x10(%rsp), %rdi
callq 0xe2a0
movq 0x38(%rsp), %rdi
callq 0xe20a
movl %ebx, %eax
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
testq %r15, %r15
jns 0x1a960
movq 0xd542(%rip), %r13      # 0x27ff8
movq (%r13), %rdi
leaq 0x59f7(%rip), %rsi      # 0x204b8
leaq 0x5a3e(%rip), %r12      # 0x20506
movq %r12, %rdx
xorl %eax, %eax
callq 0x22c0
movq (%r13), %rdi
cvtsi2sd %rbx, %xmm0
mulsd 0x58ad(%rip), %xmm0     # 0x20390
leaq 0x5a2c(%rip), %rsi      # 0x20516
movq %r12, %rdx
movb $0x1, %al
callq 0x22c0
movq (%r13), %rdi
cvtsi2sd %r15, %xmm0
mulsd 0x588b(%rip), %xmm0     # 0x20390
leaq 0x5a28(%rip), %rsi      # 0x20534
movq %r12, %rdx
movb $0x1, %al
callq 0x22c0
pushq $0xf
jmp 0x1a923
movq 0x90(%rsp), %rbx
movq %r15, %rbp
movq 0x88(%rsp), %r15
movsd 0x3ae8(%rip), %xmm0     # 0x1e620
movq %r13, %rdi
movq 0x10(%rsp), %r12
movq %r12, %rsi
xorl %edx, %edx
callq 0xba4d
movq %r12, %rdi
movq %r15, %rsi
callq 0x1a6d0
movq %rax, %r15
movq (%rbp), %rdi
leaq 0x5a84(%rip), %rsi      # 0x205e7
leaq 0x599c(%rip), %rdx      # 0x20506
xorl %eax, %eax
callq 0x22c0
movsd 0x40(%rsp), %xmm1
movq %r13, %rdi
movq %r12, %rsi
movsd 0x3a9b(%rip), %xmm0     # 0x1e620
movq %r15, %rdx
callq 0x1a4ec
movq %rax, %rbp
movq %r15, %rdi
callq 0x2060
movq 0x18(%rbp), %r15
movq %rbp, %rdi
movsd 0x3a79(%rip), %xmm0     # 0x1e620
movsd 0x4c91(%rip), %xmm1     # 0x1f840
movapd %xmm0, %xmm2
xorl %esi, %esi
callq 0x6a00
movq %rbp, %rdi
callq 0x6c1f
movq %rbp, %rdi
callq 0x6d03
movq %rbp, %rdi
callq 0x6dab
movq %rbp, %rdi
callq 0x6f89
movq %rbp, %rdi
callq 0x7068
movq %rbp, %rdi
callq 0x7165
movq %rbp, %rdi
callq 0x7269
movq %rbp, %rdi
callq 0x6f14
movq 0x18(%rbp), %rax
cmpq %r15, %rax
movq %rax, %r15
jne 0x1ab9c
movq %rbp, %rdi
callq 0x7335
movq 0x8(%rbp), %rsi
movq %rbp, %rdi
callq 0x73a1
movq %rax, %r15
testq %rbx, %rbx
je 0x1ac66
movq %rbx, %rdi
callq 0x2160
leaq 0x5(%rax), %rdi
callq 0x2330
movq %rax, %r12
leaq 0x59dd(%rip), %rsi      # 0x2061a
movq %rax, %rdi
movq %rbx, %rdx
xorl %eax, %eax
callq 0x24a0
leaq 0x33bf(%rip), %rsi      # 0x1e010
movq %r12, %rdi
callq 0x23e0
movq %rax, %rbx
movq %r12, %rdi
callq 0x2060
jmp 0x1ac7c
leaq 0x59b4(%rip), %rdi      # 0x20621
leaq 0x339c(%rip), %rsi      # 0x1e010
callq 0x23e0
movq %rax, %rbx
pushq $0x1
popq %r12
testq %rbx, %rbx
je 0x1acb3
movq %r15, %rdi
movq %rbx, %rsi
callq 0x110b6
movq %rbx, %rdi
callq 0x2150
xorl %r12d, %r12d
movq %r15, %rdi
callq 0xe2a0
movq %rbp, %rdi
callq 0x5db8
movl %r12d, %ebx
jmp 0x1a9f2
movq 0xd33e(%rip), %rax      # 0x27ff8
movq (%rax), %rdi
leaq 0x5971(%rip), %rsi      # 0x20635
leaq 0x583b(%rip), %rdx      # 0x20506
xorl %eax, %eax
callq 0x22c0
jmp 0x1ac9b