/*
* BinaryCovarionModel.java
*
* Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard
*
* This file is part of BEAST.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* BEAST is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* BEAST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BEAST; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package dr.evomodel.substmodel;
import dr.evomodelxml.substmodel.BinaryCovarionModelParser;
import dr.evolution.datatype.TwoStateCovarion;
import dr.oldevomodel.substmodel.SubstitutionModelUtils;
import dr.inference.model.Parameter;
/**
* @author Alexei Drummond
* @author Marc A. Suchard
* <p/>
* a the rate of the slow rate class
* 1 the rate of the fast rate class
* p0 the equilibrium frequency of zero states
* p1 1 - p0, the equilibrium frequency of one states
* f0 the equilibrium frequency of slow rate class
* f1 1 - f0, the equilibrium frequency of fast rate class
* s the rate of switching
* <p/>
* then the (unnormalized) instantaneous rate matrix (unnormalized Q) should be
* <p/>
* [ -(a*p1)-s , a*p1 , s , 0 ]
* [ a*p0 , -(a*p0)-s , 0 , s ]
* [ s , 0 , -p1-s , p1 ]
* [ 0 , s , p0 , -p0-s ]
*/
public class BinaryCovarionModel extends AbstractCovarionModel {
/**
* @param dataType the data type
* @param frequencies the frequencies of the visible states
* @param hiddenFrequencies the frequencies of the hidden rates
* @param alphaParameter the rate of evolution in slow mode
* @param switchingParameter the rate of flipping between slow and fast modes
*/
public BinaryCovarionModel(TwoStateCovarion dataType,
Parameter frequencies,
Parameter hiddenFrequencies,
Parameter alphaParameter,
Parameter switchingParameter,
dr.oldevomodel.substmodel.BinaryCovarionModel.Version version) {
super(BinaryCovarionModelParser.COVARION_MODEL, dataType, frequencies, hiddenFrequencies);
this.alpha = alphaParameter;
this.switchRate = switchingParameter;
this.frequencies = frequencies;
this.hiddenFrequencies = hiddenFrequencies;
this.version = version;
addVariable(alpha);
addVariable(switchRate);
addVariable(frequencies);
addVariable(hiddenFrequencies);
}
protected void setupQMatrix(double[] rates, double[] pi, double[][] unnormalizedQ) {
double a = alpha.getParameterValue(0);
double s = switchRate.getParameterValue(0);
double f0 = hiddenFrequencies.getParameterValue(0);
double f1 = hiddenFrequencies.getParameterValue(1);
double p0 = frequencies.getParameterValue(0); // TODO Use pi[0], ..., pi[3]
double p1 = frequencies.getParameterValue(1);
assert Math.abs(1.0 - f0 - f1) < 1e-8;
assert Math.abs(1.0 - p0 - p1) < 1e-8;
f0 = version.getF0(f0);
f1 = version.getF1(f1);
unnormalizedQ[0][1] = a * p1;
unnormalizedQ[0][2] = s * f0;
unnormalizedQ[0][3] = 0.0;
unnormalizedQ[1][0] = a * p0;
unnormalizedQ[1][2] = 0.0;
unnormalizedQ[1][3] = s * f0;
unnormalizedQ[2][0] = s * f1;
unnormalizedQ[2][1] = 0.0;
unnormalizedQ[2][3] = p1;
unnormalizedQ[3][0] = 0.0;
unnormalizedQ[3][1] = s * f1;
unnormalizedQ[3][2] = p0;
}
protected void frequenciesChanged() {
}
protected void ratesChanged() {
}
public String toString() {
final int stateCount = dataType.getStateCount();
double[] tmp = new double[stateCount * stateCount];
getInfinitesimalMatrix(tmp);
double[][] q = new double[stateCount][stateCount];
for (int i = 0; i < stateCount; ++i) {
for (int j = 0; j < stateCount; ++j) {
q[i][j] = tmp[i * stateCount + j];
}
}
setupQMatrix(null, null, q);
return SubstitutionModelUtils.toString(q, dataType, 2);
}
/**
* Normalize rate matrix to one expected substitution per unit time
*
* @param matrix the matrix to normalize to one expected substitution
* @param pi the equilibrium distribution of states
*/
protected double getNormalizationValue(double[][] matrix, double[] pi) {
double subst = 0.0;
int dimension = pi.length;
for (int i = 0; i < dimension; i++) {
subst += -matrix[i][i] * pi[i];
}
// normalize, including switches
for (int i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
matrix[i][j] = matrix[i][j] / subst;
}
}
double switchingProportion = 0.0;
switchingProportion += matrix[0][2] * pi[2];
switchingProportion += matrix[2][0] * pi[0];
switchingProportion += matrix[1][3] * pi[3];
switchingProportion += matrix[3][1] * pi[1];
// normalize, removing switches
for (int i = 0; i < dimension; i++) {
for (int j = 0; j < dimension; j++) {
matrix[i][j] = matrix[i][j] / (1.0 - switchingProportion);
}
}
return 1.0; // Already normalized
}
private Parameter alpha;
private Parameter switchRate;
private Parameter frequencies;
private Parameter hiddenFrequencies;
final private dr.oldevomodel.substmodel.BinaryCovarionModel.Version version;
}