package statalign.model.ext; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; import statalign.base.InputData; import statalign.base.MainManager; import statalign.base.Mcmc; import statalign.base.Tree; import statalign.base.Utils; import statalign.base.Vertex; import statalign.base.hmm.Hmm; import statalign.io.DataType; import statalign.mcmc.McmcMove; import statalign.model.subst.SubstitutionModel; /** * Interface between StatAlign core and the {@link ModelExtension} plugins. * Not visible to plugins. * * @author novak */ public class ModelExtManager { private MainManager mainMan; private Mcmc mcmc; private List<ModelExtension> pluginList; private List<ModelExtension> activeList; private String filenameExtensionBase = ""; public void addToFilenameExtension(String s) { if (filenameExtensionBase.isEmpty()) { filenameExtensionBase += s; } else { filenameExtensionBase += "_"+s; } } public String getFilenameExtension() { return filenameExtensionBase; } private int[] propWeights; /** Plugin selected for proposing parameter change */ ModelExtension selectedPlugin; public ModelExtManager(MainManager mainMan) { this.mainMan = mainMan; } /** * Discovers model extension plugins and initialises them. */ public void init(ArrayList<String> args) { pluginList = Utils.findPlugins(ModelExtension.class); for(ModelExtension plugin : pluginList) { plugin.setManager(this); } if (args != null) { ARG: for(int i = 0 ; i < args.size() ; ) { String [] pluginPair = args.get(i).split("\\[",2); for(ModelExtension plugin : pluginList) { if (plugin.getPluginID().equals(pluginPair[0])) { plugin.setActive(true); if (pluginPair.length == 2) { // Then we have some parameters if (pluginPair[1].endsWith("]")) { String paramString = pluginPair[1].substring(0,pluginPair[1].length()-1); String [] paramList = paramString.split(",", -1); for (String param : paramList) { String [] paramPair = param.split("=", 2); if (paramPair.length == 2) { plugin.setParam(paramPair[0],paramPair[1]); } else { plugin.setParam(paramPair[0],true); } } } else { throw new IllegalArgumentException( "Plugin parameters must be specifed in the form\n-plugin:pluginName[par1=x,par2=y]\n"); } } plugin.init(); ++i; continue ARG; } } String s = ""; for(ModelExtension plugin : pluginList) { s += plugin.getPluginID()+" ("+(plugin.active?"active":"inactive")+")\n"; } System.out.println("\nUnrecognised plugin: "+pluginPair[0]+"\n" +"Available plugins:\n" +s); throw new IllegalArgumentException("Unrecognised plugin: "+pluginPair[0]); } } } /** * Determines the list of active {@link ModelExtension} plugins. * Calls {@link ModelExtension#initRun(statalign.base.InputData)} on each of them. * @param inputData input data */ public void initRun(InputData inputData) throws IllegalArgumentException { activeList = new ArrayList<ModelExtension>(); for(ModelExtension plugin : pluginList) { if(plugin.isActive()) { if (!activeList.contains(plugin)) activeList.add(plugin); plugin.initRun(inputData); plugin.initMcmc(inputData); } } propWeights = new int[activeList.size()]; } public void setMcmc(Mcmc mcmc) { this.mcmc = mcmc; for(ModelExtension plugin : pluginList) { plugin.setMcmc(mcmc); } } /** * Allows access to the Mcmc class. Generally not recommended. */ public Mcmc getMcmc() { return mcmc; } /** * Calls {@link ModelExtension#beforeSampling(Tree)} on each active plugin. * @param tree current tree */ public void beforeSampling(Tree tree) { for(ModelExtension plugin : activeList) plugin.beforeSampling(tree); } public void afterSampling() { for(ModelExtension plugin : activeList) plugin.afterSampling(); } /** * Calculates the total log-likelihood of the state by adding the log-likelihood factor * contributions from all model extension plugins to the log-likelihood of the tree. * @param tree the current tree * @return the total log-likelihood */ public double totalLogLike(Tree tree) { double ll = tree.getLogLike(); //double ll = 0.0; for(ModelExtension plugin : activeList) { ll += plugin.logLikeFactor(tree); } return ll; } /** * Calculates the log of total prior probability by including contributions from model extension plugins. * @param tree the current tree * @return the log of total prior probability */ public double totalLogPrior(Tree tree) { double ll = tree.getLogPrior(); //double ll = 0.0; for(ModelExtension plugin : activeList) ll += plugin.logPrior(tree); return ll; } public int getParamChangeWeight() { int i = 0, total = 0; for(ModelExtension plugin : activeList) total += (propWeights[i++] = plugin.getParamChangeWeight()); return total; } public String getMcmcInfo() { String info = ""; for(ModelExtension plugin : activeList) { info += "\n"+plugin.getPluginID()+"\n\n"; info += plugin.getMcmcInfo(); } return info; } public void beforeModExtParamChange(Tree tree) { selectedPlugin = activeList.get(Utils.weightedChoose(propWeights)); selectedPlugin.beforeModExtParamChange(tree, selectedPlugin); for(ModelExtension plugin : activeList) if(plugin != selectedPlugin) plugin.beforeModExtParamChange(tree, selectedPlugin); } public boolean proposeParamChange(Tree tree) { return selectedPlugin.proposeParamChange(tree); } public boolean isParamChangeAccepted(double logProposalRatio,McmcMove m) { mcmc.coreModel.setLogLike(logLikeModExtParamChange(mcmc.tree)); return mcmc.isParamChangeAccepted(logProposalRatio,m); } public void modifyProposalWidths() { for(ModelExtension modExt : activeList) { modExt.modifyProposalWidths(); } } public void zeroAllMoveCounts() { for(ModelExtension modExt : activeList) { modExt.zeroAllMoveCounts(); } } // public void resetAll() { // for(ModelExtension modExt : activeList) { // ModelExtension m = modExt.reset(); // if (m != null) modExt = m; // m.init(); // } // } /** * Calculates the total log-likelihood of the state by adding the log-likelihood factor * contributions from all model extension plugins to the log-likelihood of the tree. * @param tree the current tree * @return the total log-likelihood */ public double logLikeModExtParamChange(Tree tree) { double ll = tree.getLogLike(); //double ll = 0.0; for(ModelExtension plugin : activeList) ll += plugin.logLikeModExtParamChange(tree, selectedPlugin); return ll; } public void afterModExtParamChange(Tree tree, boolean accepted) { selectedPlugin.afterModExtParamChange(tree, selectedPlugin, accepted); for(ModelExtension plugin : activeList) if(plugin != selectedPlugin) plugin.afterModExtParamChange(tree, selectedPlugin, accepted); } public void beforeAlignChange(Tree tree, Vertex selectRoot) { for(ModelExtension plugin : activeList) plugin.beforeAlignChange(tree, selectRoot); } /** * Calculates the total log-likelihood of the state by adding the log-likelihood factor * contributions from all model extension plugins to the log-likelihood of the tree. * @param tree the current tree * @return the total log-likelihood */ public double logLikeAlignChange(Tree tree, Vertex selectRoot) { double ll = tree.getLogLike(); //double ll = 0.0; for(ModelExtension plugin : activeList) ll += plugin.logLikeAlignChange(tree, selectRoot); return ll; } public void afterAlignChange(Tree tree, Vertex selectRoot, boolean accepted) { for(ModelExtension plugin : activeList) plugin.afterAlignChange(tree, selectRoot, accepted); } public void beforeTreeChange(Tree tree, Vertex nephew) { for(ModelExtension plugin : activeList) plugin.beforeTreeChange(tree, nephew); } /** * Calculates the total log-likelihood of the state by adding the log-likelihood factor * contributions from all model extension plugins to the log-likelihood of the tree. * @param tree the current tree * @return the total log-likelihood */ public double logLikeTreeChange(Tree tree, Vertex nephew) { double ll = tree.getLogLike(); //double ll = 0.0; for(ModelExtension plugin : activeList) { ll += plugin.logLikeTreeChange(tree, nephew); } return ll; } public void afterTreeChange(Tree tree, Vertex nephew, boolean accepted) { for(ModelExtension plugin : activeList) plugin.afterTreeChange(tree, nephew, accepted); } public void beforeEdgeLenChange(Tree tree, Vertex vertex) { for(ModelExtension plugin : activeList) plugin.beforeEdgeLenChange(tree, vertex); } /** * Calculates the total log-likelihood of the state by adding the log-likelihood factor * contributions from all model extension plugins to the log-likelihood of the tree. * @param tree the current tree * @return the total log-likelihood */ public double logLikeEdgeLenChange(Tree tree, Vertex vertex) { double ll = tree.getLogLike(); //double ll = 0.0; for(ModelExtension plugin : activeList) ll += plugin.logLikeEdgeLenChange(tree, vertex); return ll; } public void afterEdgeLenChange(Tree tree, Vertex vertex, boolean accepted) { for(ModelExtension plugin : activeList) plugin.afterEdgeLenChange(tree, vertex, accepted); } public void beforeIndelParamChange(Tree tree, Hmm hmm, McmcMove m) { for(ModelExtension plugin : activeList) plugin.beforeIndelParamChange(tree, hmm, m); } /** * Calculates the total log-likelihood of the state by adding the log-likelihood factor * contributions from all model extension plugins to the log-likelihood of the tree. * @param tree the current tree * @return the total log-likelihood */ public double logLikeIndelParamChange(Tree tree, Hmm hmm, McmcMove m) { double ll = tree.getLogLike(); //double ll = 0.0; for(ModelExtension plugin : activeList) ll += plugin.logLikeIndelParamChange(tree, hmm, m); return ll; } public void afterIndelParamChange(Tree tree, Hmm hmm, McmcMove m, boolean accepted) { for(ModelExtension plugin : activeList) plugin.afterIndelParamChange(tree, hmm, m, accepted); } public void beforeSubstParamChange(Tree tree, SubstitutionModel model, int ind) { for(ModelExtension plugin : activeList) plugin.beforeSubstParamChange(tree, model, ind); } /** * Calculates the total log-likelihood of the state by adding the log-likelihood factor * contributions from all model extension plugins to the log-likelihood of the tree. * @param tree the current tree * @return the total log-likelihood */ public double logLikeSubstParamChange(Tree tree, SubstitutionModel model, int ind) { double ll = tree.getLogLike(); //double ll = 0.0; for(ModelExtension plugin : activeList) ll += plugin.logLikeSubstParamChange(tree, model, ind); return ll; } public void afterSubstParamChange(Tree tree, SubstitutionModel model, int ind, boolean accepted) { for(ModelExtension plugin : activeList) plugin.afterSubstParamChange(tree, model, ind, accepted); } /** * Returns the (unmodifiable) list of recognised {@link ModelExtension} plugins. */ public List<ModelExtension> getPluginList() { return Collections.unmodifiableList(pluginList); } public void afterFirstHalfBurnin() { for(ModelExtension plugin : activeList) plugin.afterFirstHalfBurnin(); } public void afterBurnin() { for(ModelExtension plugin : activeList) plugin.afterBurnin(); } public void incrementWeights() { for(ModelExtension plugin : activeList) plugin.incrementWeights(); } /** * * @param aligned Vector indicating which characters are aligned to the current * column in the subtrees below. * @return Logarithm of emission probability for subtrees */ public double calcLogEm(int[] aligned) { double logEm = 0; for(ModelExtension plugin : activeList) { logEm += plugin.calcLogEm(aligned); } return logEm; } /** * Called in GUI mode only when new data is added to the analysis. * This is transferred to the plugins to allow them to respond. */ public void dataAdded(File file, DataType data) { for(ModelExtension plugin : pluginList) { plugin.dataAdded(file, data); } } }