// File: /workspace/github_c_makefile_star2_O3/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, 0x38(%rsp)
movl %r9d, %r12d
movq %rcx, 0x28(%rsp)
movq %rdx, 0x20(%rsp)
movq %rsi, %rbx
movl %r8d, %esi
callq 0x12d2b
movq %rax, %r15
movq %rax, %rdi
testq %rbx, %rbx
jne 0x1f4fe
callq 0x132af
jmp 0x1f50b
movq %rbx, %rsi
movl $0x1, %edx
callq 0x1373c
movq %rax, 0x10(%rsp)
movq 0xb0(%rsp), %rbx
movl 0x98(%rsp), %esi
cmpl $0x0, 0xb8(%rsp)
jne 0x1f557
movq 0x10(%rsp), %rdi
movl %esi, %r13d
movl $0x1, %edx
callq 0xd8c1
movq %rax, %r14
testq %rbx, %rbx
js 0x1f6b1
cmpq %rbx, %r14
ja 0x1f6ba
movq %r15, 0x18(%rsp)
jmp 0x1f562
movl %esi, %r13d
movq %r15, 0x18(%rsp)
xorl %r14d, %r14d
movl 0xa8(%rsp), %r15d
movq 0x80(%rsp), %rbp
movq 0xca7f(%rip), %rax      # 0x2bff8
movq (%rax), %rdi
leaq 0x516f(%rip), %rsi      # 0x246f2
leaq 0x511c(%rip), %rdx      # 0x246a6
xorl %eax, %eax
callq 0x22c0
movzbl %r12b, %r12d
movl %r12d, (%rsp)
movq 0x20(%rsp), %rdi
movq 0x28(%rsp), %rsi
movq 0x10(%rsp), %rdx
movq %rbp, %rcx
movl %r13d, %r8d
movl $0x1, %r9d
callq 0xd97c
movq %rax, 0x30(%rsp)
movq %rax, %rdi
movl %r15d, %esi
movsd 0x38(%rsp), %xmm0
callq 0xea9a
movq %rax, %r15
testq %rax, %rax
jne 0x1f5e7
callq 0x4219
movl $0xe, %r14d
jmp 0x1f6e7
cmpl $0x0, 0xb8(%rsp)
jne 0x1f617
subq %r14, %rbx
movl 0x20(%r15), %edx
movq 0x10(%rsp), %rdi
movl %r13d, %esi
callq 0xd66f
testq %rbx, %rbx
js 0x1f6cd
cmpq %rbx, %rax
ja 0x1f6d6
movq 0xa0(%rsp), %rbx
movq 0xc9d2(%rip), %rax      # 0x2bff8
movq (%rax), %rdi
leaq 0x5132(%rip), %rsi      # 0x24762
leaq 0x506f(%rip), %rdx      # 0x246a6
xorl %eax, %eax
callq 0x22c0
movl 0x20(%r15), %r9d
movl %r12d, (%rsp)
movq 0x20(%rsp), %rdi
movq 0x28(%rsp), %rsi
movq 0x10(%rsp), %rdx
movq 0x80(%rsp), %rcx
movl %r13d, %ebp
movl %r13d, %r8d
callq 0xdeec
movq %rax, %r13
xorps %xmm0, %xmm0
cvtsi2sd %ebp, %xmm0
movsd 0x8(%rax), %xmm1
divsd %xmm0, %xmm1
divsd %xmm0, %xmm1
movsd %xmm1, (%rbx)
movsd 0x2fdd(%rip), %xmm0     # 0x22668
leaq 0x40(%rsp), %rcx
movq %rax, %rdi
movq %r15, %rsi
movl $0x1, %edx
callq 0xf24f
movl %eax, %r14d
testl %eax, %eax
je 0x1f722
movq %r13, %rdi
callq 0xd14d
jmp 0x1f6e7
testq %r14, %r14
jns 0x1f550
movq %rbx, %rdi
movq %r14, %rsi
callq 0x4238
movl $0xf, %r14d
jmp 0x1f6fe
testq %rax, %rax
jns 0x1f617
movq %rbx, %rdi
movq %rax, %rsi
callq 0x4199
movl $0xf, %r14d
movq %r15, %rdi
callq 0xea48
movq 0x30(%rsp), %rdi
callq 0xd0f0
movq 0x18(%rsp), %r15
movq 0x10(%rsp), %rdi
callq 0x122d1
movq %r15, %rdi
callq 0x12233
movl %r14d, %eax
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x90(%rsp), %r14
movq 0x88(%rsp), %rbx
movsd 0x2f2e(%rip), %xmm0     # 0x22668
movq %r13, %rdi
movq 0x10(%rsp), %r12
movq %r12, %rsi
xorl %edx, %edx
callq 0xf9a9
movq %r12, %rdi
movq %rbx, %rsi
callq 0x1f389
movq %rax, %rbx
movq 0xc897(%rip), %rax      # 0x2bff8
movq (%rax), %rdi
leaq 0x501c(%rip), %rsi      # 0x24787
leaq 0x4f34(%rip), %rdx      # 0x246a6
xorl %eax, %eax
callq 0x22c0
movsd 0x40(%rsp), %xmm1
movq %r13, %rdi
movq %r12, %rsi
movsd 0x2edb(%rip), %xmm0     # 0x22668
movq %rbx, %rdx
callq 0x1f194
movq %rax, %rbp
movq %rbx, %rdi
callq 0x2060
movq 0x18(%rbp), %rbx
movq %rbp, %rdi
movsd 0x2eb9(%rip), %xmm0     # 0x22668
movsd 0x4141(%rip), %xmm1     # 0x238f8
movaps %xmm0, %xmm2
xorl %esi, %esi
callq 0x99af
movq %rbp, %rdi
callq 0x9c82
movq %rbp, %rdi
callq 0x9dc8
movq %rbp, %rdi
callq 0x9eea
movq %rbp, %rdi
callq 0xa371
movq %rbp, %rdi
callq 0xa4d7
movq %rbp, %rdi
callq 0xa767
movq %rbp, %rdi
callq 0xa8dd
movq %rbp, %rdi
callq 0xa24d
movq 0x18(%rbp), %rax
cmpq %rbx, %rax
movq %rax, %rbx
jne 0x1f7a4
movq %rbp, %rdi
callq 0xaa3d
movq 0x8(%rbp), %rsi
movq %rbp, %rdi
callq 0xab26
movq %rax, %rbx
testq %r14, %r14
je 0x1f86d
movq %r14, %rdi
callq 0x2160
leaq 0x5(%rax), %rdi
callq 0x2330
movq %rax, %r12
leaq 0x4f76(%rip), %rsi      # 0x247ba
movq %rax, %rdi
movq %r14, %rdx
xorl %eax, %eax
callq 0x24a0
leaq 0x27b8(%rip), %rsi      # 0x22010
movq %r12, %rdi
callq 0x23e0
movq %rax, %r14
movq %r12, %rdi
callq 0x2060
jmp 0x1f883
leaq 0x4f4d(%rip), %rdi      # 0x247c1
leaq 0x2795(%rip), %rsi      # 0x22010
callq 0x23e0
movq %rax, %r14
testq %r14, %r14
je 0x1f8b3
movq %rbx, %rdi
movq %r14, %rsi
callq 0x15dca
movq %r14, %rdi
callq 0x2150
xorl %r14d, %r14d
movq %rbx, %rdi
callq 0x122d1
movq %rbp, %rdi
callq 0x86c7
jmp 0x1f6a7
callq 0x4174
movl $0x1, %r14d
jmp 0x1f89e