mirror of
https://github.com/chhylp123/hifiasm.git
synced 2026-09-15 12:47:57 +08:00
922 lines
23 KiB
C++
922 lines
23 KiB
C++
#define __STDC_LIMIT_MACROS
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
///#include "partig.h"
|
|
#include "rcut.h"
|
|
#include "Purge_Dups.h"
|
|
#include "Correct.h"
|
|
#include "ksort.h"
|
|
|
|
#define mc_edge_key(e) ((e).x)
|
|
KRADIX_SORT_INIT(mce, mc_edge_t, mc_edge_key, member_size(mc_edge_t, x))
|
|
#define mc_generic_key(x) (x)
|
|
KRADIX_SORT_INIT(mc64, uint64_t, mc_generic_key, 8)
|
|
|
|
#define pt_a(x, id) ((x).ma.a + ((x).idx.a[(id)]>>32))
|
|
#define pt_n(x, id) ((uint32_t)((x).idx.a[(id)]))
|
|
#define ma_x(z) (((z).x>>32))
|
|
#define ma_y(z) (((uint32_t)((z).x)))
|
|
|
|
|
|
typedef struct {
|
|
int32_t max_iter;
|
|
int32_t n_perturb;
|
|
double f_perturb;
|
|
uint64_t seed;
|
|
} mc_opt_t;
|
|
|
|
typedef struct {
|
|
t_w_t z[2];
|
|
} mc_pairsc_t;
|
|
|
|
typedef struct {
|
|
uint64_t x; // RNG
|
|
uint32_t cc_off, cc_size;
|
|
///uint32_t n_cc_edge, m_cc_edge;
|
|
///uint64_t *cc_edge;
|
|
kvec_t(uint64_t) cc_edge;
|
|
uint32_t n_sub;
|
|
uint32_t *cc_node;
|
|
uint32_t *bfs, *bfs_mark;
|
|
mc_pairsc_t *z, *z_opt;///keep scores to nodes(1) and nodes(-1)
|
|
int8_t *s, *s_opt;
|
|
} mc_svaux_t;
|
|
|
|
void mc_opt_init(mc_opt_t *opt)
|
|
{
|
|
memset(opt, 0, sizeof(mc_opt_t));
|
|
opt->n_perturb = 5000;
|
|
opt->f_perturb = 0.1;
|
|
opt->max_iter = 1000;
|
|
opt->seed = 11;
|
|
}
|
|
|
|
mc_g_t *init_mc_g_t(ma_ug_t *ug, asg_t *read_g)
|
|
{
|
|
mc_g_t *p = NULL; CALLOC(p, 1);
|
|
p->ug = ug;
|
|
p->rg = read_g;
|
|
kv_init(p->s);
|
|
CALLOC(p->s.a, ug->g->n_seq);
|
|
p->s.n = p->s.m = ug->g->n_seq;
|
|
return p;
|
|
}
|
|
|
|
void destory_mc_g_t(mc_g_t **p)
|
|
{
|
|
if(!p || !(*p)) return;
|
|
kv_destroy((*p)->s);
|
|
if((*p)->e)
|
|
{
|
|
kv_destroy((*p)->e->idx);
|
|
kv_destroy((*p)->e->ma);
|
|
free((*p)->e->cc);
|
|
free((*p)->e);
|
|
}
|
|
free((*p));
|
|
}
|
|
|
|
|
|
static inline uint64_t kr_splitmix64(uint64_t x)
|
|
{
|
|
uint64_t z = (x += 0x9E3779B97F4A7C15ULL);
|
|
z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ULL;
|
|
z = (z ^ (z >> 27)) * 0x94D049BB133111EBULL;
|
|
return z ^ (z >> 31);
|
|
}
|
|
|
|
static inline double kr_drand_r(uint64_t *x)
|
|
{
|
|
union { uint64_t i; double d; } u;
|
|
*x = kr_splitmix64(*x);
|
|
u.i = 0x3FFULL << 52 | (*x) >> 12;
|
|
return u.d - 1.0;
|
|
}
|
|
|
|
static void ks_shuffle_uint32_t(size_t n, uint32_t a[], uint64_t *x)
|
|
{
|
|
size_t i, j;
|
|
for (i = n; i > 1; --i) {
|
|
uint32_t tmp;
|
|
j = (size_t)(kr_drand_r(x) * i);
|
|
tmp = a[j]; a[j] = a[i-1]; a[i-1] = tmp;
|
|
}
|
|
}
|
|
|
|
void mc_merge_dup(mc_g_t *mg) // MUST BE sorted
|
|
{
|
|
uint32_t i, j, k, st;
|
|
w_t w;
|
|
for (st = 0, i = 1, k = 0; i <= mg->e->ma.n; ++i) {
|
|
if (i == mg->e->ma.n || mg->e->ma.a[i].x != mg->e->ma.a[st].x) {
|
|
if (i - st > 1) {
|
|
for (j = st, w = 0; j < i; ++j) {
|
|
w += mg->e->ma.a[j].w;
|
|
}
|
|
mg->e->ma.a[k] = mg->e->ma.a[st];
|
|
mg->e->ma.a[k++].w = w;
|
|
} else mg->e->ma.a[k++] = mg->e->ma.a[st];
|
|
st = i;
|
|
}
|
|
}
|
|
mg->e->ma.n = k;
|
|
}
|
|
|
|
static void mc_edges_idx(mc_match_t *ma)
|
|
{
|
|
uint32_t st, i;
|
|
kv_resize(uint64_t, ma->idx, ma->n_seq);
|
|
ma->idx.n = ma->n_seq;
|
|
memset(ma->idx.a, 0, ma->idx.n*sizeof(uint64_t));
|
|
for (st = 0, i = 1; i <= ma->ma.n; ++i)
|
|
if (i == ma->ma.n || (ma->ma.a[i].x>>32) != (ma->ma.a[st].x>>32))
|
|
ma->idx.a[ma->ma.a[st].x>>32] = (uint64_t)st << 32 | (i - st), st = i;
|
|
}
|
|
|
|
static mc_edge_t *get_mc_edge(const mc_match_t *ma, uint32_t sid1, uint32_t sid2)
|
|
{
|
|
mc_edge_t *o = pt_a(*ma, sid1);
|
|
uint32_t n = pt_n(*ma, sid1), k;
|
|
for (k = 0; k < n; ++k)
|
|
if (((uint32_t)o[k].x) == sid2)
|
|
return &(o[k]);
|
|
return NULL;
|
|
}
|
|
|
|
static void normalize_mc_edge(mc_edge_t *a, mc_edge_t *b)
|
|
{
|
|
if(a->w >= b->w)
|
|
{
|
|
b->x = (uint32_t)a->x;
|
|
b->x <<= 32;
|
|
b->x |= (a->x>>32);
|
|
b->w = a->w;
|
|
}
|
|
else
|
|
{
|
|
a->x = (uint32_t)b->x;
|
|
a->x <<= 32;
|
|
a->x |= (b->x>>32);
|
|
a->w = b->w;
|
|
}
|
|
}
|
|
|
|
uint32_t mc_edges_symm(mc_match_t *ma)
|
|
{
|
|
uint8_t *del = NULL;
|
|
uint32_t i, k, n = 0;
|
|
mc_edge_t *t = NULL, *m = NULL;
|
|
CALLOC(del, ma->ma.n);
|
|
|
|
for (i = 0; i < ma->ma.n; ++i) {
|
|
m = &ma->ma.a[i];
|
|
if (ma_x(*m) == ma_y(*m))
|
|
{
|
|
del[i] = 1, ++n;///self overlap
|
|
continue;
|
|
}
|
|
t = get_mc_edge(ma, ma_y(*m), ma_x(*m));
|
|
if(!t)
|
|
{
|
|
del[i] = 1, ++n;///self overlap
|
|
continue;
|
|
}
|
|
normalize_mc_edge(m, t);
|
|
}
|
|
|
|
if (n > 0) {
|
|
for (i = k = 0; i < ma->ma.n; ++i)
|
|
if (!del[i]) ma->ma.a[k++] = ma->ma.a[i];
|
|
ma->ma.n = k;
|
|
mc_edges_idx(ma);
|
|
}
|
|
|
|
free(del);
|
|
return n;
|
|
}
|
|
|
|
void debug_mc_interval_t(mc_interval_t *p, uint32_t p_n, uint32_t *p_idx, ma_ug_t *ug, asg_t *rg,
|
|
trans_chain* t_ch)
|
|
{
|
|
fprintf(stderr, "0----------[M::%s]----------\n", __func__);
|
|
uint32_t i, offset, v, sid, eid, spos, epos, p_status, p_uid, occ;
|
|
ma_utg_t *u = NULL;
|
|
mc_interval_t *a = NULL, *t = NULL;
|
|
|
|
for (v = 0; v < ug->u.n; v++)
|
|
{
|
|
a = p + p_idx[v];
|
|
occ = p_idx[v+1] - p_idx[v];
|
|
for (i = 0; i < occ; i++)
|
|
{
|
|
if(a[i].uID != v) fprintf(stderr, "ERROR-s\n");
|
|
}
|
|
}
|
|
|
|
for (v = 0, p_status = (uint32_t)-1, p_uid = (uint32_t)-1; v < p_n; v++)
|
|
{
|
|
t = &(p[v]);
|
|
sid = t->nS;
|
|
eid = t->nE;
|
|
spos = t->bS;
|
|
epos = t->bE;
|
|
if(p_uid == t->uID && p_status == t->hs)
|
|
{
|
|
fprintf(stderr, "ERROR-a\n");
|
|
}
|
|
p_status = t->hs;
|
|
p_uid = t->uID;
|
|
u = &(ug->u.a[t->uID]);
|
|
for (i = offset = 0; i < u->n; i++)
|
|
{
|
|
if(i == sid)
|
|
{
|
|
if(spos != offset)
|
|
{
|
|
fprintf(stderr, "ERROR-b\n");
|
|
}
|
|
}
|
|
|
|
if(i == eid)
|
|
{
|
|
if(epos != (offset+rg->seq[u->a[i]>>33].len - 1))
|
|
{
|
|
fprintf(stderr, "ERROR-c, real end: %u\n",
|
|
(uint32_t)(offset+rg->seq[u->a[i]>>33].len - 1));
|
|
}
|
|
}
|
|
|
|
offset += (uint32_t)u->a[i];
|
|
if(i >= sid && i <= eid)
|
|
{
|
|
if(t_ch->is_r_het[u->a[i]>>33] != t->hs)
|
|
{
|
|
fprintf(stderr, "ERROR-d: is_r_het: %u, h_status: %u\n", t_ch->is_r_het[u->a[i]>>33], t->hs);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void update_mc_edges(mc_g_t *mg, hap_overlaps_list* ha, kv_u_trans_t *ta, trans_chain* t_ch, double f_rate)
|
|
{
|
|
uint32_t v, i, k, qn, tn, qs, qe, ts, te, occ, as, ae, l, offset, l_pos;
|
|
uint64_t hetLen, homLen, oLen;
|
|
mc_interval_t *a = NULL;
|
|
mc_edge_t *ma = NULL;
|
|
asg_t* nsg = mg->ug->g;
|
|
ma_utg_t *u = NULL;
|
|
mc_interval_t *t = NULL;
|
|
|
|
kvec_t(mc_interval_t) p; kv_init(p);
|
|
kvec_t(uint32_t) p_idx; kv_init(p_idx);
|
|
if(t_ch)
|
|
{
|
|
kv_push(uint32_t, p_idx, 0);
|
|
for (v = 0; v < nsg->n_seq; v++)
|
|
{
|
|
u = &(mg->ug->u.a[v]);
|
|
for (k = 1, l = 0, offset = 0, l_pos = 0; k <= u->n; ++k)
|
|
{
|
|
if (k == u->n || t_ch->is_r_het[u->a[k]>>33] != t_ch->is_r_het[u->a[l]>>33])
|
|
{
|
|
kv_pushp(mc_interval_t, p, &t);
|
|
t->uID = v;
|
|
t->hs = t_ch->is_r_het[u->a[l]>>33];
|
|
|
|
t->bS = l_pos;
|
|
t->bE = offset + mg->rg->seq[u->a[k-1]>>33].len - 1;
|
|
|
|
t->nS = l;
|
|
t->nE = k - 1;
|
|
l = k;
|
|
l_pos = offset + (uint32_t)u->a[k-1];
|
|
}
|
|
offset += (uint32_t)u->a[k-1];
|
|
}
|
|
kv_push(uint32_t, p_idx, p.n);
|
|
}
|
|
|
|
debug_mc_interval_t(p.a, p.n, p_idx.a, mg->ug, mg->rg, t_ch);
|
|
}
|
|
|
|
if(!mg->e)
|
|
{
|
|
CALLOC(mg->e, 1);
|
|
mg->e->n_seq = mg->ug->g->n_seq;
|
|
kv_init(mg->e->idx); kv_init(mg->e->ma);
|
|
}
|
|
|
|
if(ha)
|
|
{
|
|
for (v = 0; v < ha->num; v++)
|
|
{
|
|
for (i = 0; i < ha->x[v].a.n; i++)
|
|
{
|
|
if(ha->x[v].a.a[i].score <= 0) continue;
|
|
if(ha->x[v].a.a[i].xUid == ha->x[v].a.a[i].yUid) continue;
|
|
if(p.n > 0 && p_idx.n > 0)
|
|
{
|
|
/*****************qn*****************/
|
|
qn = ha->x[v].a.a[i].xUid;
|
|
qs = ha->x[v].a.a[i].x_beg_pos;
|
|
qe = ha->x[v].a.a[i].x_end_pos - 1;
|
|
|
|
a = p.a + p_idx.a[qn];
|
|
occ = p_idx.a[qn+1] - p_idx.a[qn];
|
|
for (k = 0, hetLen = 0, homLen = 0; k < occ; k++)
|
|
{
|
|
as = a[k].bS;
|
|
ae = a[k].bE;
|
|
oLen = ((MIN(qe, ae) >= MAX(qs, as))? MIN(qe, ae) - MAX(qs, as) + 1 : 0);
|
|
if(homLen + hetLen > 0 && oLen == 0) break;
|
|
if(oLen == 0) continue;
|
|
if(a[k].hs == N_HET)
|
|
{
|
|
homLen += oLen;
|
|
}
|
|
else if(asm_opt.polyploidy <= 2 && (a[k].hs&P_HET))///if(asm_opt.polyploidy <= 2 && (a[k].hs&S_HET))
|
|
{
|
|
homLen += oLen;
|
|
}
|
|
else
|
|
{
|
|
hetLen += oLen;
|
|
}
|
|
}
|
|
|
|
if(hetLen <= ((hetLen + homLen)*f_rate)) continue;
|
|
/*****************qn*****************/
|
|
|
|
|
|
/*****************tn*****************/
|
|
tn = ha->x[v].a.a[i].yUid;
|
|
ts = ha->x[v].a.a[i].y_beg_pos;
|
|
te = ha->x[v].a.a[i].y_end_pos - 1;
|
|
|
|
a = p.a + p_idx.a[tn];
|
|
occ = p_idx.a[tn+1] - p_idx.a[tn];
|
|
for (k = 0, hetLen = 0, homLen = 0; k < occ; k++)
|
|
{
|
|
as = a[k].bS;
|
|
ae = a[k].bE;
|
|
oLen = ((MIN(te, ae) >= MAX(ts, as))? MIN(te, ae) - MAX(ts, as) + 1 : 0);
|
|
if(homLen + hetLen > 0 && oLen == 0) break;
|
|
if(oLen == 0) continue;
|
|
if(a[k].hs == N_HET)
|
|
{
|
|
homLen += oLen;
|
|
}
|
|
else if(asm_opt.polyploidy <= 2 && (a[k].hs&P_HET))///if(asm_opt.polyploidy <= 2 && (a[k].hs&S_HET))
|
|
{
|
|
homLen += oLen;
|
|
}
|
|
else
|
|
{
|
|
hetLen += oLen;
|
|
}
|
|
}
|
|
|
|
if(hetLen <= ((hetLen + homLen)*f_rate)) continue;
|
|
/*****************tn*****************/
|
|
}
|
|
kv_pushp(mc_edge_t, mg->e->ma, &ma);
|
|
ma->x = (uint64_t)ha->x[v].a.a[i].xUid << 32 | ha->x[v].a.a[i].yUid;
|
|
ma->w = ha->x[v].a.a[i].score;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(ta)
|
|
{
|
|
for (i = 0; i < ta->n; ++i)
|
|
{
|
|
if(ta->a[i].del) continue;
|
|
if(p.n > 0 && p_idx.n > 0)
|
|
{
|
|
/*****************qn*****************/
|
|
qn = ta->a[i].qn;
|
|
qs = ta->a[i].qs;
|
|
qe = ta->a[i].qe - 1;
|
|
|
|
a = p.a + p_idx.a[qn];
|
|
occ = p_idx.a[qn+1] - p_idx.a[qn];
|
|
for (k = 0, hetLen = 0, homLen = 0; k < occ; k++)
|
|
{
|
|
as = a[k].bS;
|
|
ae = a[k].bE;
|
|
oLen = ((MIN(qe, ae) >= MAX(qs, as))? MIN(qe, ae) - MAX(qs, as) + 1 : 0);
|
|
if(homLen + hetLen > 0 && oLen == 0) break;
|
|
if(oLen == 0) continue;
|
|
if(a[k].hs == N_HET)
|
|
{
|
|
homLen += oLen;
|
|
}
|
|
else if(asm_opt.polyploidy <= 2 && (a[k].hs&P_HET))///if(asm_opt.polyploidy <= 2 && (a[k].hs&S_HET))
|
|
{
|
|
homLen += oLen;
|
|
}
|
|
else
|
|
{
|
|
hetLen += oLen;
|
|
}
|
|
}
|
|
|
|
if(hetLen <= ((hetLen + homLen)*f_rate)) continue;
|
|
/*****************qn*****************/
|
|
|
|
/*****************tn*****************/
|
|
tn = ta->a[i].tn;
|
|
ts = ta->a[i].ts;
|
|
te = ta->a[i].te - 1;
|
|
|
|
a = p.a + p_idx.a[tn];
|
|
occ = p_idx.a[tn+1] - p_idx.a[tn];
|
|
for (k = 0, hetLen = 0, homLen = 0; k < occ; k++)
|
|
{
|
|
as = a[k].bS;
|
|
ae = a[k].bE;
|
|
oLen = ((MIN(te, ae) >= MAX(ts, as))? MIN(te, ae) - MAX(ts, as) + 1 : 0);
|
|
if(homLen + hetLen > 0 && oLen == 0) break;
|
|
if(oLen == 0) continue;
|
|
if(a[k].hs == N_HET)
|
|
{
|
|
homLen += oLen;
|
|
}
|
|
else if(asm_opt.polyploidy <= 2 && (a[k].hs&P_HET))///if(asm_opt.polyploidy <= 2 && (a[k].hs&S_HET))
|
|
{
|
|
homLen += oLen;
|
|
}
|
|
else
|
|
{
|
|
hetLen += oLen;
|
|
}
|
|
}
|
|
|
|
if(hetLen <= ((hetLen + homLen)*f_rate)) continue;
|
|
/*****************tn*****************/
|
|
kv_pushp(mc_edge_t, mg->e->ma, &ma);
|
|
ma->x = (uint64_t)ta->a[i].qn << 32 | ta->a[i].tn;
|
|
ma->w = ta->a[i].nw;
|
|
}
|
|
}
|
|
}
|
|
|
|
radix_sort_mce(mg->e->ma.a, mg->e->ma.a + mg->e->ma.n);
|
|
mc_merge_dup(mg);
|
|
mc_edges_idx(mg->e);
|
|
mc_edges_symm(mg->e);
|
|
kv_destroy(p); kv_destroy(p_idx);
|
|
}
|
|
|
|
void debug_mc_g_t(mc_g_t *mg)
|
|
{
|
|
fprintf(stderr, "0----------[M::%s]----------\n", __func__);
|
|
mc_edge_t *o = NULL, *s = NULL;
|
|
uint32_t i, k, n, cnt;
|
|
for (i = 0; i < mg->e->n_seq; ++i)
|
|
{
|
|
o = pt_a(*(mg->e), i); n = pt_n(*(mg->e), i);
|
|
for (k = 0; k < n; ++k)
|
|
{
|
|
if(ma_x(o[k]) != i) fprintf(stderr, "ERROR-g\n");
|
|
s = get_mc_edge(mg->e, ma_y(o[k]), ma_x(o[k]));
|
|
if(!s) fprintf(stderr, "ERROR-e\n");
|
|
if(s)
|
|
{
|
|
if(!(ma_x(*s) == ma_y(o[k]) && ma_y(*s) == ma_x(o[k]) && s->w == o[k].w))
|
|
{
|
|
fprintf(stderr, "ERROR-f\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
for (k = cnt = 0; k < mg->e->ma.n; ++k)
|
|
{
|
|
if(ma_x(mg->e->ma.a[k]) == i) cnt++;
|
|
}
|
|
|
|
if(cnt != n) fprintf(stderr, "ERROR-h\n");
|
|
}
|
|
}
|
|
|
|
uint64_t *mc_g_cc_core(mc_match_t *ma)
|
|
{
|
|
uint32_t i, x, y, *flag;
|
|
uint64_t *group;
|
|
mc_edge_t *o = NULL;
|
|
kvec_t(uint32_t) stack; kv_init(stack);
|
|
|
|
MALLOC(flag, ma->n_seq);
|
|
for (i = 0; i < ma->n_seq; ++i)
|
|
flag[i] = (uint32_t)-1;
|
|
|
|
// connected componets
|
|
for (i = 0; i < ma->n_seq; ++i) {
|
|
if (flag[i] != (uint32_t)-1) continue;
|
|
stack.n = 0;
|
|
kv_push(uint32_t, stack, i);
|
|
while (stack.n > 0) {
|
|
uint32_t k, j, n;
|
|
stack.n--;
|
|
k = stack.a[stack.n];
|
|
flag[k] = i;///group id
|
|
// n = (uint32_t)ma->idx[k];
|
|
// s = ma->idx[k] >> 32;
|
|
o = pt_a(*ma, k);
|
|
n = pt_n(*ma, k);
|
|
for (j = 0; j < n; ++j) {
|
|
uint32_t t = ma_y(o[j]);
|
|
if (flag[t] != (uint32_t)-1) continue;
|
|
// if (ns == ms) PT_EXPAND(stack, ms);
|
|
// stack[ns++] = t;
|
|
kv_push(uint32_t, stack, t);
|
|
}
|
|
}
|
|
}
|
|
kv_destroy(stack);
|
|
|
|
// precalculate the size of each group
|
|
CALLOC(group, ma->n_seq);
|
|
for (i = 0; i < ma->n_seq; ++i)
|
|
group[i] = (uint64_t)flag[i] << 32 | i;
|
|
radix_sort_mc64(group, group + ma->n_seq);
|
|
for (i = 1, x = y = 0; i <= ma->n_seq; ++i) {
|
|
if (i == ma->n_seq || group[i]>>32 != group[x]>>32) {
|
|
uint32_t j;
|
|
for (j = x; j < i; ++j)
|
|
group[j] = (uint64_t)y << 32 | (uint32_t)group[j];///(group id)|first element in this group
|
|
++y, x = i;
|
|
}
|
|
}
|
|
free(flag);
|
|
return group;
|
|
}
|
|
|
|
void mc_g_cc(mc_match_t *ma)
|
|
{
|
|
ma->cc = mc_g_cc_core(ma);
|
|
}
|
|
|
|
mc_svaux_t *mc_svaux_init(const mc_g_t *mg, uint64_t x)
|
|
{
|
|
uint32_t st, i, max_cc = 0;
|
|
mc_match_t *ma = mg->e;
|
|
mc_svaux_t *b;
|
|
CALLOC(b, 1);
|
|
b->x = x;
|
|
for (st = 0, i = 1; i <= ma->n_seq; ++i)
|
|
if (i == ma->n_seq || ma->cc[st]>>32 != ma->cc[i]>>32)
|
|
max_cc = max_cc > i - st? max_cc : i - st, st = i;
|
|
kv_init(b->cc_edge);
|
|
MALLOC(b->cc_node, max_cc);
|
|
///CALLOC(b->s, ma->n_seq);
|
|
b->s = mg->s.a;
|
|
CALLOC(b->s_opt, ma->n_seq);
|
|
MALLOC(b->bfs, ma->n_seq);
|
|
MALLOC(b->bfs_mark, ma->n_seq);
|
|
CALLOC(b->z, ma->n_seq);
|
|
CALLOC(b->z_opt, ma->n_seq);
|
|
return b;
|
|
}
|
|
void mc_svaux_destroy(mc_svaux_t *b)
|
|
{
|
|
b->s = NULL;
|
|
kv_destroy(b->cc_edge); free(b->cc_node);
|
|
free(b->s); free(b->s_opt);
|
|
free(b->z); free(b->z_opt);
|
|
free(b->bfs); free(b->bfs_mark);
|
|
free(b);
|
|
}
|
|
|
|
t_w_t mc_score(const mc_match_t *ma, mc_svaux_t *b)
|
|
{
|
|
uint32_t i;
|
|
t_w_t z = 0;
|
|
for (i = 0; i < b->cc_size; ++i) {
|
|
uint32_t k = (uint32_t)ma->cc[b->cc_off + i];///uid
|
|
z += -((t_w_t)(b->s[k])) * (b->z[k].z[0] - b->z[k].z[1]);
|
|
}
|
|
return z;
|
|
}
|
|
|
|
void mc_reset_z(const mc_match_t *ma, mc_svaux_t *b)
|
|
{
|
|
uint32_t i;
|
|
for (i = 0; i < b->cc_size; ++i) {
|
|
uint32_t k = (uint32_t)ma->cc[b->cc_off + i];///uid
|
|
uint32_t o = ma->idx.a[k] >> 32;
|
|
uint32_t j, n = (uint32_t)ma->idx.a[k];
|
|
b->z[k].z[0] = b->z[k].z[1] = 0;
|
|
for (j = 0; j < n; ++j) {
|
|
const mc_edge_t *e = &ma->ma.a[o + j];
|
|
uint32_t t = ma_y(*e);
|
|
if (b->s[t] > 0) b->z[k].z[0] += e->w;
|
|
else if (b->s[t] < 0) b->z[k].z[1] += e->w;
|
|
}
|
|
}
|
|
}
|
|
|
|
t_w_t mc_init_spin(const mc_opt_t *opt, const mc_match_t *ma, mc_svaux_t *b)
|
|
{
|
|
uint32_t i;
|
|
b->cc_edge.n = 0;
|
|
for (i = 0; i < b->cc_size; ++i) {///how many nodes
|
|
uint32_t k = (uint32_t)ma->cc[b->cc_off + i];///node id
|
|
uint32_t o = ma->idx.a[k] >> 32;///cc group id
|
|
uint32_t n = (uint32_t)ma->idx.a[k], j;
|
|
b->cc_node[i] = k;
|
|
for (j = 0; j < n; ++j) {
|
|
w_t w = ma->ma.a[o + j].w;
|
|
w = w > 0? w : -w;
|
|
kv_push(uint64_t, b->cc_edge, (uint64_t)((uint32_t)-1 - ((uint32_t)w)) << 32 | (o + j));
|
|
///b->cc_edge[b->n_cc_edge++] = (uint64_t)((uint32_t)-1 - w) << 32 | (o + j);
|
|
}
|
|
}
|
|
radix_sort_mc64(b->cc_edge.a, b->cc_edge.a + b->cc_edge.n);
|
|
for (i = 0; i < b->cc_edge.n; ++i) { // from the strongest edge to the weakest
|
|
const mc_edge_t *e = &ma->ma.a[(uint32_t)b->cc_edge.a[i]];
|
|
uint32_t n1 = ma_x(*e), n2 = ma_y(*e);
|
|
if (b->s[n1] == 0 && b->s[n2] == 0) {
|
|
b->x = kr_splitmix64(b->x);
|
|
b->s[n1] = b->x&1? 1 : -1;
|
|
b->s[n2] = e->w > 0? -b->s[n1] : b->s[n1];
|
|
}/****************************may have bugs********************************/
|
|
else if(b->s[n1] == 0)
|
|
{
|
|
b->s[n1] = e->w > 0? -b->s[n2] : b->s[n2];
|
|
}
|
|
else if(b->s[n2] == 0)
|
|
{
|
|
b->s[n2] = e->w > 0? -b->s[n1] : b->s[n1];
|
|
}
|
|
/****************************may have bugs********************************/
|
|
}
|
|
mc_reset_z(ma, b);
|
|
return mc_score(ma, b);
|
|
}
|
|
///k is uid
|
|
static void mc_set_spin(const mc_match_t *ma, mc_svaux_t *b, uint32_t k, int8_t s)
|
|
{
|
|
uint32_t o, j, n;
|
|
int8_t s0 = b->s[k];
|
|
if (s0 == s) return;
|
|
o = ma->idx.a[k] >> 32;
|
|
n = (uint32_t)ma->idx.a[k];
|
|
for (j = 0; j < n; ++j) {
|
|
const mc_edge_t *e = &ma->ma.a[o + j];
|
|
uint32_t t = ma_y(*e);///1->z[0]; (-1)->z[1];
|
|
if (s0 != 0) b->z[t].z[(s0 < 0)] -= e->w;
|
|
if (s != 0) b->z[t].z[(s < 0)] += e->w;
|
|
}
|
|
b->s[k] = s;
|
|
}
|
|
|
|
static t_w_t mc_optimize_local(const mc_opt_t *opt, const mc_match_t *ma, mc_svaux_t *b, uint32_t *n_iter)
|
|
{
|
|
int32_t n_iter_local = 0;
|
|
while (n_iter_local < opt->max_iter) {
|
|
uint32_t i, n_flip = 0;
|
|
++(*n_iter);
|
|
ks_shuffle_uint32_t(b->cc_size, b->cc_node, &b->x);
|
|
for (i = 0; i < b->cc_size; ++i) {
|
|
uint32_t k = b->cc_node[i];///uid
|
|
int8_t s;
|
|
if (b->z[k].z[0] == b->z[k].z[1]) continue;
|
|
s = b->z[k].z[0] > b->z[k].z[1]? -1 : 1;
|
|
if (b->s[k] != s) {
|
|
mc_set_spin(ma, b, k, s);///no need to change the score of k itself
|
|
++n_flip;
|
|
}
|
|
}
|
|
++n_iter_local;
|
|
if (n_flip == 0) break;
|
|
}
|
|
return mc_score(ma, b);
|
|
}
|
|
|
|
static void mc_perturb(const mc_opt_t *opt, const mc_match_t *ma, mc_svaux_t *b)
|
|
{
|
|
uint32_t i;
|
|
for (i = 0; i < b->cc_size; ++i) {
|
|
uint32_t k = (uint32_t)ma->cc[b->cc_off + i];///node id
|
|
double y;
|
|
y = kr_drand_r(&b->x);
|
|
if (y < opt->f_perturb)
|
|
mc_set_spin(ma, b, k, -b->s[k]);
|
|
}
|
|
}
|
|
|
|
static uint32_t mc_bfs(const mc_match_t *ma, mc_svaux_t *b, uint32_t k0, uint32_t bfs_round, uint32_t max_size)
|
|
{
|
|
uint32_t i, n_bfs = 0, st, en, r;
|
|
b->bfs[n_bfs++] = k0, b->bfs_mark[k0] = k0;
|
|
st = 0, en = n_bfs;
|
|
for (r = 0; r < bfs_round; ++r) {
|
|
for (i = st; i < en; ++i) {
|
|
uint32_t k = b->bfs[i];
|
|
uint32_t o = ma->idx.a[k] >> 32;
|
|
uint32_t n = (uint32_t)ma->idx.a[k], j;
|
|
for (j = 0; j < n; ++j) {
|
|
uint32_t t = (uint32_t)ma->ma.a[o + j].x;
|
|
if (b->bfs_mark[t] != k0)
|
|
b->bfs[n_bfs++] = t, b->bfs_mark[t] = k0;
|
|
}
|
|
}
|
|
st = en, en = n_bfs;
|
|
if (max_size > 0 && n_bfs > max_size) break;
|
|
}
|
|
return n_bfs;
|
|
}
|
|
|
|
///bfs_round is 3
|
|
static void mc_perturb_node(const mc_opt_t *opt, const mc_match_t *ma, mc_svaux_t *b, int32_t bfs_round)
|
|
{
|
|
uint32_t i, k, n_bfs = 0;
|
|
k = (uint32_t)(kr_drand_r(&b->x) * b->cc_size + .499);
|
|
k = (uint32_t)ma->cc[b->cc_off + k];///node id
|
|
n_bfs = mc_bfs(ma, b, k, bfs_round, (int32_t)(b->cc_size * opt->f_perturb));
|
|
for (i = 0; i < n_bfs; ++i)
|
|
mc_set_spin(ma, b, b->bfs[i], -b->s[b->bfs[i]]);
|
|
}
|
|
|
|
uint32_t mc_solve_cc(const mc_opt_t *opt, const mc_g_t *mg, mc_svaux_t *b, uint32_t cc_off, uint32_t cc_size)
|
|
{
|
|
uint32_t j, k, n_iter = 0;
|
|
t_w_t /**sc_ori,**/ sc_opt = -(1<<30), sc;///problem-w
|
|
|
|
b->cc_off = cc_off, b->cc_size = cc_size;
|
|
if (b->cc_size < 2) return 0;
|
|
|
|
// first guess
|
|
/**sc_ori =**/ mc_init_spin(opt, mg->e, b);
|
|
if (b->cc_size == 2) return 0;
|
|
|
|
// optimize
|
|
sc_opt = mc_optimize_local(opt, mg->e, b, &n_iter);
|
|
for (j = 0; j < b->cc_size; ++j) {///backup s and z in s_opt and z_opt
|
|
b->s_opt[b->cc_node[j]] = b->s[b->cc_node[j]]; ///hap status of each unitig
|
|
b->z_opt[b->cc_node[j]] = b->z[b->cc_node[j]]; ///z[0]: positive weight; z[1]: positive weight
|
|
}
|
|
for (k = 0; k < (uint32_t)opt->n_perturb; ++k) {
|
|
if (k&1) mc_perturb(opt, mg->e, b);
|
|
else mc_perturb_node(opt, mg->e, b, 3);
|
|
sc = mc_optimize_local(opt, mg->e, b, &n_iter);
|
|
if (sc > sc_opt) {
|
|
for (j = 0; j < b->cc_size; ++j) {
|
|
b->s_opt[b->cc_node[j]] = b->s[b->cc_node[j]];
|
|
b->z_opt[b->cc_node[j]] = b->z[b->cc_node[j]];
|
|
}
|
|
sc_opt = sc;
|
|
} else {
|
|
for (j = 0; j < b->cc_size; ++j) {
|
|
b->s[b->cc_node[j]] = b->s_opt[b->cc_node[j]];
|
|
b->z[b->cc_node[j]] = b->z_opt[b->cc_node[j]];
|
|
}
|
|
}
|
|
}
|
|
for (j = 0; j < b->cc_size; ++j)
|
|
b->s[b->cc_node[j]] = b->s_opt[b->cc_node[j]];
|
|
return n_iter;
|
|
}
|
|
|
|
void mc_solve_core(const mc_opt_t *opt, mc_g_t *mg)
|
|
{
|
|
double index_time = yak_realtime();
|
|
uint32_t st, i;
|
|
mc_svaux_t *b;
|
|
mc_g_cc(mg->e);
|
|
b = mc_svaux_init(mg, opt->seed);
|
|
for (st = 0, i = 1; i <= mg->e->n_seq; ++i) {
|
|
if (i == mg->e->n_seq || mg->e->cc[st]>>32 != mg->e->cc[i]>>32) {
|
|
mc_solve_cc(opt, mg, b, st, i - st);
|
|
st = i;
|
|
}
|
|
}
|
|
///mc_write_info(g, b);
|
|
mc_svaux_destroy(b);
|
|
fprintf(stderr, "[M::%s::%.3f] ==> Partition\n", __func__, yak_realtime()-index_time);
|
|
}
|
|
|
|
void set_p_flag(mc_g_t *mg, uint32_t uID, uint8_t* trio_flag, trans_chain* t_ch, int8_t s)
|
|
{
|
|
uint32_t i;
|
|
ma_utg_t *u = &(mg->ug->u.a[uID]);
|
|
for (i = 0; i < u->n; i++)
|
|
{
|
|
trio_flag[u->a[i]>>33] |= SET_TRIO;
|
|
if(t_ch->is_r_het[u->a[i]>>33] == N_HET) continue;
|
|
if(s == 0)
|
|
{
|
|
if(t_ch->is_r_het[u->a[i]>>33]&P_HET)//special case
|
|
{
|
|
trio_flag[u->a[i]>>33] |= FATHER;
|
|
}
|
|
continue;
|
|
}
|
|
trio_flag[u->a[i]>>33] |= (s > 0? FATHER:MOTHER);
|
|
}
|
|
}
|
|
|
|
void filter_ovlp_by_mc(ma_ug_t *ug, asg_t *read_g, uint32_t uID, hap_overlaps_list* ha, mc_match_t *ma,
|
|
int8_t *s)
|
|
{
|
|
mc_edge_t *o = pt_a(*ma, uID);
|
|
uint32_t n = pt_n(*ma, uID), k, qn, tn;
|
|
hap_overlaps *p = NULL;
|
|
int index;
|
|
|
|
for (k = 0; k < n; ++k)
|
|
{
|
|
qn = ma_x(o[k]); tn = ma_y(o[k]); p = NULL;
|
|
if((s[qn]*s[tn])!=-1) continue;
|
|
index = get_specific_hap_overlap(&(ha->x[qn]), qn, tn);
|
|
if(index != -1 && ha->x[qn].a.a[index].score == (long long)o[k].w)
|
|
{
|
|
p = &(ha->x[qn].a.a[index]);
|
|
}
|
|
else
|
|
{
|
|
index = get_specific_hap_overlap(&(ha->x[tn]), tn, qn);
|
|
if(index != -1 && ha->x[tn].a.a[index].score == (long long)o[k].w)
|
|
{
|
|
p = &(ha->x[tn].a.a[index]);
|
|
}
|
|
}
|
|
if(!p) fprintf(stderr, "ERROR\n");
|
|
p->status = FLIP;
|
|
}
|
|
}
|
|
|
|
void clean_ovlp_by_mc(mc_g_t *mg, hap_overlaps_list* ha)
|
|
{
|
|
uint32_t v, i, k, qn, tn, types[4];
|
|
types[X2Y] = Y2X; types[Y2X] = X2Y; types[XCY] = YCX; types[YCX] = XCY;
|
|
int index;
|
|
hap_overlaps *x = NULL, *y = NULL;
|
|
for (i = 0; i < mg->e->n_seq; ++i)
|
|
{
|
|
filter_ovlp_by_mc(mg->ug, mg->rg, i, ha, mg->e, mg->s.a);
|
|
}
|
|
|
|
for (v = 0; v < ha->num; v++)
|
|
{
|
|
for (i = 0; i < ha->x[v].a.n; i++)
|
|
{
|
|
qn = ha->x[v].a.a[i].xUid;
|
|
tn = ha->x[v].a.a[i].yUid;
|
|
x = &(ha->x[v].a.a[i]);
|
|
if(x->status != FLIP) continue;
|
|
index = get_specific_hap_overlap(&(ha->x[tn]), tn, qn);
|
|
if(index != -1)
|
|
{
|
|
y = &(ha->x[tn].a.a[index]);
|
|
set_reverse_hap_overlap(y, x, types);
|
|
y->status = FLIP;
|
|
}
|
|
if(index == -1) fprintf(stderr, "ERROR\n");
|
|
}
|
|
}
|
|
|
|
for (v = 0; v < ha->num; v++)
|
|
{
|
|
for (i = k = 0; i < ha->x[v].a.n; i++)
|
|
{
|
|
if(ha->x[v].a.a[i].status != FLIP) continue;
|
|
|
|
ha->x[v].a.a[k] = ha->x[v].a.a[i];
|
|
k++;
|
|
}
|
|
ha->x[v].a.n = k;
|
|
}
|
|
}
|
|
|
|
|
|
void p_nodes(mc_g_t *mg, trans_chain* t_ch, uint8_t* trio_flag)
|
|
{
|
|
uint32_t i;
|
|
for (i = 0; i < mg->e->n_seq; ++i)
|
|
{
|
|
set_p_flag(mg, i, trio_flag, t_ch, mg->s.a[i]);
|
|
}
|
|
}
|
|
|
|
void mc_solve(hap_overlaps_list* ovlp, trans_chain* t_ch, kv_u_trans_t *ta, ma_ug_t *ug, asg_t *read_g, double f_rate, uint8_t* trio_flag)
|
|
{
|
|
mc_opt_t opt;
|
|
mc_opt_init(&opt);
|
|
mc_g_t *mg = init_mc_g_t(ug, read_g);
|
|
update_mc_edges(mg, ovlp, ta, t_ch, f_rate);
|
|
debug_mc_g_t(mg);
|
|
mc_solve_core(&opt, mg);
|
|
|
|
if((asm_opt.flag & HA_F_PARTITION) && t_ch)
|
|
{
|
|
p_nodes(mg, t_ch, trio_flag);
|
|
}
|
|
|
|
if(ovlp) clean_ovlp_by_mc(mg, ovlp);
|
|
|
|
|
|
destory_mc_g_t(&mg);
|
|
} |