package beast.evolution.substitutionmodel; import java.util.Arrays; import beast.core.Description; import beast.core.Input.Validate; import beast.evolution.datatype.DataType; import beast.evolution.datatype.Nucleotide; import beast.evolution.tree.Node; @Description("Jukes Cantor substitution model: all rates equal and " + "uniformly distributed frequencies") public class JukesCantor extends SubstitutionModel.Base { public JukesCantor() { // this is added to avoid a parsing error inherited from superclass because frequencies are not provided. frequenciesInput.setRule(Validate.OPTIONAL); try { // this call will be made twice when constructed from XML // but this ensures that the object is validly constructed for testing purposes. initAndValidate(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("initAndValidate() call failed when constructing JukesCantor()"); } } double[] frequencies; EigenDecomposition eigenDecomposition; @Override public void initAndValidate() { double[] eval = new double[]{0.0, -1.3333333333333333, -1.3333333333333333, -1.3333333333333333}; double[] evec = new double[]{1.0, 2.0, 0.0, 0.5, 1.0, -2.0, 0.5, 0.0, 1.0, 2.0, 0.0, -0.5, 1.0, -2.0, -0.5, 0.0}; double[] ivec = new double[]{0.25, 0.25, 0.25, 0.25, 0.125, -0.125, 0.125, -0.125, 0.0, 1.0, 0.0, -1.0, 1.0, 0.0, -1.0, 0.0}; eigenDecomposition = new EigenDecomposition(evec, ivec, eval); if (frequenciesInput.get() != null) { throw new RuntimeException("Frequencies must not be specified in Jukes-Cantor model. They are assumed equal."); } frequencies = new double[]{0.25, 0.25, 0.25, 0.25}; } @Override public double[] getFrequencies() { return frequencies; } @Override public void getTransitionProbabilities(Node node, double startTime, double endTime, double rate, double[] matrix) { double delta = 4.0 / 3.0 * (startTime - endTime); double pStay = (1.0 + 3.0 * Math.exp(-delta * rate)) / 4.0; double pMove = (1.0 - Math.exp(-delta * rate)) / 4.0; // fill the matrix with move probabilities Arrays.fill(matrix, pMove); // fill the diagonal for (int i = 0; i < 4; i++) { matrix[i * 5] = pStay; } } @Override public EigenDecomposition getEigenDecomposition(Node node) { return eigenDecomposition; } @Override public boolean canHandleDataType(DataType dataType) { return dataType instanceof Nucleotide; } }