package statalign.base.mcmc;
import statalign.base.Tree;
import statalign.base.Utils;
import statalign.base.Vertex;
import statalign.mcmc.McmcModule;
import statalign.mcmc.McmcMove;
public class SilentIndelMove extends McmcMove {
Tree tree = null;
Vertex v;
double[] weights;
//final static double LEAFCOUNT_POWER = 2.0;
final static double LEAFCOUNT_POWER = 1.0; // Original
boolean didInsertion = false;
boolean validProposal = false;
public SilentIndelMove (McmcModule m, String n) {
owner = m;
name = n;
autoTune = false;
acceptAllDuringFirstHalfBurnin = true;
}
public void copyState(Object externalState) {
//Utils.DEBUG = true;
if (externalState instanceof Tree) {
if (tree == null) {
tree = (Tree) externalState;
}
}
else throw new IllegalArgumentException("SilentIndelMove.copyState must take an argument of type Tree.");
weights = new double[tree.vertex.length];
tree.countLeaves();
tree.countSilentIndels();
int tot = 0;
for (int i = 0; i < weights.length; i++) {
//weights[i] = Math.pow(tree.vertex[i].leafCount, LEAFCOUNT_POWER);
//weights[i] = (tree.vertex[i].nSilentIndels > 0) ? 1 : 0;
weights[i] = (tree.vertex[i].leafCount>1 && tree.vertex[i].nSilentIndels>0) ? 1 : 0;
tot += weights[i];
}
int k = 0;
v = null;
if (tot!=0) validProposal = true;
while (v==null || v.leafCount==1) {
//while (v==null || v == tree.root || v.parent == tree.root || v.leafCount==1) {
k = Utils.weightedChoose(weights, null);
v = tree.vertex[k];
if (Utils.DEBUG) System.out.println(k+" "+v.parent);
}
if (Utils.DEBUG) System.out.println("Vertex = "+k);
//v.saveData();
((CoreMcmcModule) owner).getModelExtMan().beforeAlignChange(tree, v);
}
public double proposal(Object externalState) {
//if (Utils.DEBUG) tree.root.printToScreenAlignment(0,0,true);
double logProposalRatio = 0;
if (validProposal && owner.isFirstHalfBurnin() && acceptAllDuringFirstHalfBurnin) {
// In first half of burnin we'll only excise silent indels
//v.modifySilentIndel(false);
v.exciseAllSilentIndels();
return 0;
}
if (!validProposal) return Double.NEGATIVE_INFINITY;
if (v.nSilentIndels==1 || Utils.generator.nextDouble() < Utils.SILENT_INSERT_PROB) {
if (Utils.DEBUG) System.out.println("Inserting silent indel.");
didInsertion = true;
//logProposalRatio = v.insertSilentIndel();
logProposalRatio = v.modifySilentIndel(didInsertion);
}
else {
if (Utils.DEBUG) System.out.println("Excising silent indel.");
didInsertion = false;
//logProposalRatio = v.exciseSilentIndel();
logProposalRatio = v.modifySilentIndel(didInsertion);
}
if (logProposalRatio == Double.NEGATIVE_INFINITY) {
validProposal = false;
}
else validProposal = true;
//if (Utils.DEBUG) tree.root.printToScreenAlignment(0,0,true);
return logProposalRatio;
}
public double logPriorDensity(Object externalState) {
return 0.0;
}
public void updateLikelihood(Object externalState) {
if (validProposal) {
v.calcFelsen();
v.calcOrphan();
v.calcIndelLogLike();
v.calcAllUp();
owner.setLogLike(((CoreMcmcModule) owner).getModelExtMan().logLikeAlignChange(tree, v));
}
}
public void restoreState(Object externalState) {
// v.restoreFiveWay(false); // currently this is the way we're saving the old state
if (validProposal) {
if (didInsertion) v.undoInsertSilentIndel();
else v.undoExciseSilentIndel();
}
//v.restoreData();
v.calcFelsen();
v.calcOrphan();
v.calcIndelLogLike();
v.calcAllUp();
// this could be problematic if the proposal failed
}
public void afterMove(Object externalState) {
//Utils.DEBUG = false;
((CoreMcmcModule) owner).getModelExtMan().afterAlignChange(tree, v,lastMoveAccepted);
}
}