/* void MH_CondDegreeTetradMixMore Select two edges with no nodes in common, A1-A2 and B1-B2, s.t. A1-B2 and B1-A2 are not edges, and propose to replace the former two by the latter two. */ void MH_CondDegreeTetradMixMore(MHproposal *MHp, Network *nwp) { Vertex A1, A2, B1, B2; if(MHp->ntoggles == 0) { /* Initialize */ MHp->ntoggles=4; return; } // Rprintf("0 %f 1 %f 2 %f 3 %f\n",MHp->inputs[0],MHp->inputs[1],MHp->inputs[2],MHp->inputs[3]); // Rprintf("0 %f 1 %f 2 %f 3 %f\n",MHp->inputs[4],MHp->inputs[5],MHp->inputs[6],MHp->inputs[7]); // Rprintf("0 %f 1 %f 2 %f 3 %f\n",MHp->inputs[8],MHp->inputs[9],MHp->inputs[10],MHp->inputs[11]); do{ GetRandEdge(&A1, &A2, nwp); GetRandEdge(&B1, &B2, nwp); //Rprintf("A1 %d A2 %d B1 %d B2 %d\n",A1,A2,B1,B2); //Rprintf("g: A1 %f A2 %f B1 %f B2 %f\n",MHp->inputs[A1-1],MHp->inputs[A2-1],MHp->inputs[B1-1],MHp->inputs[B2-1]); }while( ((fabs(MHp->inputs[A1-1]-MHp->inputs[A2-1])>0.001)||(fabs(MHp->inputs[B2-1]-MHp->inputs[B1-1])>0.001)||(fabs(MHp->inputs[A1-1]-MHp->inputs[B1-1])<0.001))|| A1==B1 || A1==B2 || A2==B1 || A2==B2 || (nwp->directed_flag ? IS_OUTEDGE(A1, B2) || IS_OUTEDGE(B1, A2) : // Directed IS_UNDIRECTED_EDGE(A1,B2) || IS_UNDIRECTED_EDGE(B1,A2) // Undirected )); //Rprintf("in A1 %d A2 %d B1 %d B2 %d\n",A1,A2,B1,B2); Rprintf("M: A1 %f A2 %f B1 %f B2 %f\n",MHp->inputs[A1-1],MHp->inputs[A2-1],MHp->inputs[B1-1],MHp->inputs[B2-1]); Mtail[0]=A1; Mhead[0]=A2; Mtail[1]=A1; Mhead[1]=B2; Mtail[2]=B1; Mhead[2]=B2; Mtail[3]=B1; Mhead[3]=A2; }
/* void MH_CondDegreeHexad Select three edges A1->A2, B1->B2, C1->C2 at random and rotate them to A1->B2, B1->C2, and C1->A2. Note that while all the *1s need to be distinct and all the *2s need to be distinct and all dyads to be created must be empty and meaningful (i.e. not loops), it's OK if A1=C2, B1=A2, and/or C1=B2. Indeed, "reversing" the cyclical triangle is the one operation that tetradic toggles can't accomplish. Note that this must *never* be called for undirected networks. */ void MH_CondDegreeHexad(MHproposal *MHp, Network *nwp) { Vertex A1, A2, B1, B2, C1, C2; if(MHp->ntoggles == 0) { /* Initialize */ MHp->ntoggles=6; return; } GetRandEdge(&A1, &A2, nwp); do{ GetRandEdge(&B1, &B2, nwp); }while(B1==A1 || B2==A1 || B2==A2 || EdgetreeSearch(A1, B2, nwp->outedges)); do{ GetRandEdge(&C1, &C2, nwp); }while(C1==A1 || C1==B1 || C1==A2 || C2==A2 || C2==B2 || C2==B1 || EdgetreeSearch(B1, C2, nwp->outedges) || EdgetreeSearch(C1, A2, nwp->outedges)); Mtail[0]=A1; Mhead[0]=A2; Mtail[1]=A1; Mhead[1]=B2; Mtail[2]=B1; Mhead[2]=B2; Mtail[3]=B1; Mhead[3]=C2; Mtail[4]=C1; Mhead[4]=C2; Mtail[5]=C1; Mhead[5]=A2; }
/* void MH_CondDegreeTetrad Select two edges with no nodes in common, A1-A2 and B1-B2, s.t. A1-B2 and B1-A2 are not edges, and propose to replace the former two by the latter two. */ void MH_CondDegreeTetrad(MHproposal *MHp, Network *nwp) { Vertex A1, A2, B1, B2; if(MHp->ntoggles == 0) { /* Initialize */ MHp->ntoggles=4; return; } //nstats = N_CHANGE_STATS; //matchvaltail = INPUT_PARAM[tail-1+2*nstats]; //matchvalhead = INPUT_PARAM[head-1+2*nstats]; do{ /* The reason the following randomization is needed is that, given the a tetrad with (only) A1-A2 and B1-B2 having edges, there are two degree-preserving proposals that can be made: to replace the edges with A1-B2 and B1-A2 or to replace with A1-B1 and A2-B2. GetRandEdge always returns tail<head for undirected networks, so a sampler that only uses GetRandEdge(&A1, &A2, nwp) misses out on potential proposals. This causes it to become trapped in bipartite or near-bipartite configurations. Bipartite networks are already bipartite, so they are not affected. Swapping A1 and A2 half the time allows either of the above proposals to be considered. */ if(!nwp->directed_flag && !nwp->bipartite && unif_rand()<0.5) GetRandEdge(&A2, &A1, nwp); else GetRandEdge(&A1, &A2, nwp); GetRandEdge(&B1, &B2, nwp); //Rprintf("A1 %d A2 %d B1 %d B2 %d\n",A1,A2,B1,B2); }while(A1==B1 || A1==B2 || A2==B1 || A2==B2 || (nwp->directed_flag ? (IS_OUTEDGE(A1, B2) || IS_OUTEDGE(B1, A2)) : // Directed (IS_UNDIRECTED_EDGE(A1,B2) || IS_UNDIRECTED_EDGE(B1,A2)) // Undirected )); //Rprintf("in A1 %d A2 %d B1 %d B2 %d\n",A1,A2,B1,B2); if(nwp->directed_flag){ Mtail[0]=A1; Mhead[0]=A2; Mtail[1]=A1; Mhead[1]=B2; Mtail[2]=B1; Mhead[2]=B2; Mtail[3]=B1; Mhead[3]=A2; }else{ Mtail[0]=MIN(A1,A2); Mhead[0]=MAX(A1,A2); Mtail[1]=MIN(A1,B2); Mhead[1]=MAX(A1,B2); Mtail[2]=MIN(B1,B2); Mhead[2]=MAX(B1,B2); Mtail[3]=MIN(B1,A2); Mhead[3]=MAX(B1,A2); } }
void MH_CondDegreeMixChangeOrig(MHproposal *MHp, Network *nwp) { Vertex A1, A2, B1, B2; int b; int bb, bbb=0; if(MHp->ntoggles == 0) { /* Initialize */ MHp->ntoggles=4; return; } // Rprintf("0 %f 1 %f 2 %f 3 %f\n",MHp->inputs[0],MHp->inputs[1],MHp->inputs[2],MHp->inputs[3]); // Rprintf("0 %f 1 %f 2 %f 3 %f\n",MHp->inputs[4],MHp->inputs[5],MHp->inputs[6],MHp->inputs[7]); // Rprintf("0 %f 1 %f 2 %f 3 %f\n",MHp->inputs[8],MHp->inputs[9],MHp->inputs[10],MHp->inputs[11]); do{ GetRandEdge(&A1, &A2, nwp); GetRandEdge(&B1, &B2, nwp); bb=(unif_rand() > 0.05); bbb++; if(bb){ // if(unif_rand() > 0.5){ // Less b=((fabs(MHp->inputs[A1-1]-MHp->inputs[A2-1])<0.001)||(fabs(MHp->inputs[B2-1]-MHp->inputs[B1-1])<0.001)||(fabs(MHp->inputs[A1-1]-MHp->inputs[B1-1])<0.001)); }else{ // More b=((fabs(MHp->inputs[A1-1]-MHp->inputs[A2-1])>0.001)||(fabs(MHp->inputs[B2-1]-MHp->inputs[B1-1])>0.001)||(fabs(MHp->inputs[A1-1]-MHp->inputs[B1-1])<0.001)); } // if(unif_rand() > 0.999){ //Rprintf("A1 %d A2 %d B1 %d B2 %d\n",A1,A2,B1,B2); //Rprintf("g: A1 %f A2 %f B1 %f B2 %f\n",MHp->inputs[A1-1],MHp->inputs[A2-1],MHp->inputs[B1-1],MHp->inputs[B2-1]); //} }while( (bbb<20) || b || A1==B1 || A1==B2 || A2==B1 || A2==B2 || (nwp->directed_flag ? IS_OUTEDGE(A1, B2) || IS_OUTEDGE(B1, A2) : // Directed IS_UNDIRECTED_EDGE(A1,B2) || IS_UNDIRECTED_EDGE(B1,A2) // Undirected )); //Rprintf("in A1 %d A2 %d B1 %d B2 %d\n",A1,A2,B1,B2); //Rprintf("%d: A1 %f A2 %f B1 %f B2 %f\n",bb,MHp->inputs[A1-1],MHp->inputs[A2-1],MHp->inputs[B1-1],MHp->inputs[B2-1]); if(bbb==20){ Mtail[0]=A1; Mhead[0]=A2; Mtail[1]=A1; Mhead[1]=A2; Mtail[2]=B1; Mhead[2]=B2; Mtail[3]=B1; Mhead[3]=B2; }else{ Mtail[0]=A1; Mhead[0]=A2; Mtail[1]=A1; Mhead[1]=B2; Mtail[2]=B1; Mhead[2]=B2; Mtail[3]=B1; Mhead[3]=A2; } }
/******************** void MH_Formation Propose ONLY edges not in the reference graph ***********************/ void MH_Formation (MHProposal *MHp, Network *nwp) { static Dyad ndyads; if(MHp->ntoggles == 0) { /* Initialize */ MHp->ntoggles=1; ndyads = DYADCOUNT(nwp->nnodes, 0, nwp->directed_flag); return; } if(nwp->nedges==ndyads && MHp->discord[0]->nedges==0){ /* Attempting formation on a complete graph. */ Mtail[0]=MH_FAILED; Mhead[0]=MH_IMPOSSIBLE; return; } BD_LOOP({ /* A dyad eligible to be formed is either a nontie in nwp[0] or a tie in MHp->discord-> */ if(unif_rand() < ((double)MHp->discord[0]->nedges)/(ndyads-nwp->nedges + MHp->discord[0]->nedges)){ // Tie in MHp->discord[0]: GetRandEdge(Mtail, Mhead, MHp->discord[0]); }else{ // Nontie in nwp[0]: GetRandNonedge(Mtail, Mhead, nwp); } });
/******************** void MH_BipartiteHammingTNT Tie/no tie: Gives at least 50% chance of proposing a toggle of an existing edge, as opposed to simple random toggles that rarely do so in sparse networks MSH: The name Hamming is a hack for the Hamming proposals It is no different the MH_BipartiteTNT ***********************/ void MH_BipartiteHammingTNT (MHproposal *MHp, Network *nwp) { /* *** don't forget, edges are (tail, head) now */ Vertex tail, head; Edge nddyads=nwp[1].nedges; int nd, nc; static double comp=0.5; static double odds; static Dyad ndyads; static Edge nnodes; static Edge nb1; if(MHp->ntoggles == 0) { /* Initialize */ MHp->ntoggles=1; odds = comp/(1.0-comp); nnodes = nwp[0].nnodes; nb1 = nwp[0].bipartite; ndyads = DYADCOUNT(nnodes, nb1, 0); return; } if (unif_rand() < comp && nddyads > 0) { /* Select a discordant dyad at random */ GetRandEdge(Mtail, Mhead, &nwp[1]); nd = nddyads; nc = ndyads-nd; /* Fixme! Not sure whether the ratio is calculated correctly here. Check out the similar ratio calculations for other TNT proposals. */ MHp->logratio += log((nd*1.0) / (odds*(nc+1))); /* MHp->ratio = (1.0*(nce-1)*(ncn-1)) / (nde*ndn*odds); */ /* MHp->ratio = 1.0; */ /* Rprintf("disconcord nd %d nc %d nddyads %d MHp->ratio %f\n", */ /* nd, nc, nddyads, MHp->ratio); */ }else{ /* select a concordant dyad at random */ do{ tail = 1 + unif_rand() * nb1; head = 1 + nb1 + unif_rand() * (nnodes - nb1); }while(EdgetreeSearch(tail,head,nwp[1].outedges)!=0); Mtail[0]=tail; Mhead[0]=head; nd = nddyads; nc = ndyads-nd; /* Fixme! Not sure whether the ratio is calculated correctly here. Check out the similar ratio calculations for other TNT proposals. */ MHp->logratio += log((odds*nc) / ((nd+1)*1.0)); /* Rprintf("concord nd %d nc %d nddyads %d MHp->ratio %f\n", */ /* nd, nc, nddyads, MHp->ratio); */ } /* Rprintf("h0 %d t0 %d h1 %d t1 %d\n", Mtail[0], Mhead[0], */ /* Mtail[1], Mhead[1]); */ }
void MH_CondB2Degree(MHproposal *MHp, Network *nwp) { Vertex A1, A2, B1; if(MHp->ntoggles == 0) { /* Initialize */ MHp->ntoggles=2; return; } do{ GetRandEdge(&A1, &A2, nwp); B1 = 1 + unif_rand() * nwp->bipartite; }while(A1==B1 || A2==B1 || EdgetreeSearch(B1, A2, nwp->outedges)); //Rprintf("A1 %d A2 %d B1 %d B2 %d\n",A1,A2,B1,B2); //Rprintf("in A1 %d A2 %d B1 %d B2 %d\n",A1,A2,B1,B2); Mtail[0]=A1; Mhead[0]=A2; Mtail[1]=B1; Mhead[1]=A2; }
void MH_CondDegreeMix(MHproposal *MHp, Network *nwp) { Vertex A11, A12, B11, B12; Vertex A21, A22, B21, B22; int bad; /* int goodtype; */ int pm, numtrys; if(MHp->ntoggles == 0) { /* Initialize */ MHp->ntoggles=8; return; } numtrys=0; pm=(unif_rand() > 0.5); if(pm){ do{ GetRandEdge(&A11, &A12, nwp); GetRandEdge(&B11, &B12, nwp); numtrys++; bad=((fabs(MHp->inputs[A11-1]-MHp->inputs[A12-1])<0.001)&(fabs(MHp->inputs[B12-1]-MHp->inputs[B11-1])<0.001)&(fabs(MHp->inputs[A11-1]-MHp->inputs[B11-1])>0.001)); /* goodtype = 2; */ }while( (numtrys<1000) && ((!bad) || A11==B11 || A11==B12 || A12==B11 || A12==B12 || (nwp->directed_flag ? IS_OUTEDGE(A11, B12) || IS_OUTEDGE(B11, A12) : // Directed IS_UNDIRECTED_EDGE(A11,B12) || IS_UNDIRECTED_EDGE(B11,A12) // Undirected ))); do{ GetRandEdge(&A21, &A22, nwp); GetRandEdge(&B21, &B22, nwp); numtrys++; bad=((fabs(MHp->inputs[A21-1]-MHp->inputs[A22-1])>0.001)&(fabs(MHp->inputs[B22-1]-MHp->inputs[B21-1])>0.001)&(fabs(MHp->inputs[A21-1]-MHp->inputs[B22-1])<0.001)); /* goodtype = 0; */ }while( (numtrys<1000) && ((!bad) || A21==B21 || A21==B22 || A22==B21 || A22==B22 || (nwp->directed_flag ? IS_OUTEDGE(A21, B22) || IS_OUTEDGE(B21, A22) : // Directed IS_UNDIRECTED_EDGE(A21,B22) || IS_UNDIRECTED_EDGE(B21,A22) // Undirected ))); }else{ do{ GetRandEdge(&A11, &A12, nwp); GetRandEdge(&B11, &B12, nwp); numtrys++; bad=((fabs(MHp->inputs[A11-1]-MHp->inputs[A12-1])<0.001)&(fabs(MHp->inputs[B12-1]-MHp->inputs[B11-1])<0.001)&(fabs(MHp->inputs[A11-1]-MHp->inputs[B11-1])<0.001)); /* goodtype = 3; */ }while( (numtrys<1000) && ((!bad) || A11==B11 || A11==B12 || A12==B11 || A12==B12 || (nwp->directed_flag ? IS_OUTEDGE(A11, B12) || IS_OUTEDGE(B11, A12) : // Directed IS_UNDIRECTED_EDGE(A11,B12) || IS_UNDIRECTED_EDGE(B11,A12) // Undirected ))); do{ GetRandEdge(&A21, &A22, nwp); GetRandEdge(&B21, &B22, nwp); numtrys++; bad=((fabs(MHp->inputs[A21-1]-MHp->inputs[A22-1])>0.001)&(fabs(MHp->inputs[B22-1]-MHp->inputs[B21-1])>0.001)&(fabs(MHp->inputs[A21-1]-MHp->inputs[B22-1])>0.001)); /* goodtype = 4;*/ }while( (numtrys<1000) && ((!bad) || A21==B21 || A21==B22 || A22==B21 || A22==B22 || (nwp->directed_flag ? IS_OUTEDGE(A21, B22) || IS_OUTEDGE(B21, A22) : // Directed IS_UNDIRECTED_EDGE(A21,B22) || IS_UNDIRECTED_EDGE(B21,A22) // Undirected ))); } //Rprintf("try %d bad %d (A1==B1 || A1==B2 || A2==B1 || A2==B2) %d edge %d\n",numtrys,bad,(A1==B1 || A1==B2 || A2==B1 || A2==B2), (IS_UNDIRECTED_EDGE(A1,B2) || IS_UNDIRECTED_EDGE(B1,A2))); //if(numtrys < 1000){ //Rprintf("A11 %d A12 %d B11 %d B12 %d numtrys %d type %d\n",A11,A12,B11,B12,numtrys,goodtype); //} if(numtrys==1000){ Mtail[0]=A11; Mhead[0]=A12; Mtail[1]=A11; Mhead[1]=A12; Mtail[2]=B11; Mhead[2]=B12; Mtail[3]=B11; Mhead[3]=B12; Mtail[4]=A21; Mhead[4]=A22; Mtail[5]=A21; Mhead[5]=A22; Mtail[6]=B21; Mhead[6]=B22; Mtail[7]=B21; Mhead[7]=B22; // MHp->toggletail[0]=MH_FAILED; // MHp->togglehead[0]=MH_UNSUCCESSFUL; }else{ Mtail[0]=A11; Mhead[0]=A12; Mtail[1]=A11; Mhead[1]=B12; Mtail[2]=B11; Mhead[2]=B12; Mtail[3]=B11; Mhead[3]=A12; Mtail[4]=A21; Mhead[4]=A22; Mtail[5]=A21; Mhead[5]=B22; Mtail[6]=B21; Mhead[6]=B22; Mtail[7]=B21; Mhead[7]=A22; } }
/******************** void MH_BipartiteHammingConstantEdges Chooses a pair of toggles - one a tie and one not. MSH: The name Hamming is a hack for the Hamming proposals It is no different the MH_BipartiteConstantEdges ***********************/ void MH_BipartiteHammingConstantEdges (MHproposal *MHp, Network *nwp) { /* *** don't forget, edges are (tail, head) now */ Vertex tail, head; Edge nedges=nwp[0].nedges, nddyads=nwp[1].nedges; int nde, ndn, nce, ncn; static double comp=0.5; static double odds; static Dyad ndyads; static Edge nnodes; static Edge nb1; if(MHp->ntoggles == 0) { /* Initialize */ MHp->ntoggles=2; odds = comp/(1.0-comp); nnodes = nwp[0].nnodes; nb1 = nwp[0].bipartite; ndyads = DYADCOUNT(nnodes, nb1, 0); return; } if (unif_rand() < comp && nddyads > 0) { /* Select a discordant pair of tie/nontie at random */ /* First, select discord edge at random */ do{ GetRandEdge(Mtail, Mhead, &nwp[1]); }while(EdgetreeSearch(Mtail[0], Mhead[0], nwp[0].outedges) == 0); tail=Mtail[0]; head=Mhead[0]; /* Next, select discord non-edge at random */ /* *** don't forget, edges are (tail, head) now */ do{ GetRandEdge(Mtail, Mhead, &nwp[1]); }while(EdgetreeSearch(Mtail[0], Mhead[0], nwp[0].outedges) != 0); Mtail[1]=Mtail[0]; Mhead[1]=Mhead[0]; Mtail[0]=tail; Mhead[0]=head; nde = nddyads / 2; ndn = nddyads / 2; nce = nedges-nde; ncn = ndyads-nedges-ndn; /* MHp->ratio = (nddyads*nddyads) / (odds*(nnodes-nddyads-2)*(nnodes-nddyads-2)); */ MHp->logratio += log((nde*ndn*1.0) / (odds*(nce+1)*(ncn+1))); /* MHp->ratio = (1.0*(nce-1)*(ncn-1)) / (nde*ndn*odds); */ /* MHp->ratio = 1.0; */ /* Rprintf("disconcord nde %d nce %d ndn %d ncn %d nddyads %d MHp->ratio %f\n", */ /* nde, nce, ndn,ncn,nddyads, MHp->ratio); */ }else{ /* First, select concordant edge at random */ do{ GetRandEdge(Mtail, Mhead, &nwp[0]); }while(EdgetreeSearch(Mtail[0], Mhead[0], nwp[1].outedges) == 0); /* Next, select concord non-edge at random */ do{ tail = 1 + unif_rand() * nb1; head = 1 + nb1 + unif_rand() * (nnodes - nb1); }while((EdgetreeSearch(tail,head,nwp[0].outedges)!=0) || (EdgetreeSearch(tail,head,nwp[1].outedges)!=0)); Mtail[1]=tail; Mhead[1]=head; nde = nddyads / 2; ndn = nddyads / 2; nce = nedges-nde; ncn = ndyads-nedges-ndn; /* MHp->ratio = ((nnodes-nddyads)*(nnodes-nddyads)) / (odds*(nddyads+2)*(nddyads+2)); */ if(nddyads > 4){ MHp->logratio += log((odds*nce*ncn) / ((nde+1)*(ndn+1)*1.0)); /* MHp->ratio = ((nde+1)*(ndn+1)*odds) / (1.0*nce*ncn); */ }else{ MHp->logratio += 100000000.0; } /* Rprintf("concord nde %d nce %d ndn %d ncn %d nddyads %d MHp->ratio %f\n", */ /* nde, nce, ndn,ncn,nddyads, MHp->ratio); */ } /* Rprintf("h0 %d t0 %d h1 %d t1 %d\n", Mtail[0], Mhead[0], */ /* Mtail[1], Mhead[1]); */ }