package statalign.model.subst.plugins;
import java.io.IOException;
import statalign.model.subst.plugins.NucleotideModel;
import statalign.model.subst.plugins.NucleotideModelUtils;
import statalign.base.*;
/**
* This class implements the Felsenstein 1984 parameter model.
*
* @author lyngsoe
*/
public class Felsenstein84 extends NucleotideModel{
public static final String menuName = "Felsenstein 1984";
//static final double span = 0.1; // largest parameter change when resampling
/**
* This constructor uses numerical methods to diagonalise the rate
* matrix and to set diagonalising matrices.
* @throws IOException
*/
public Felsenstein84() throws IOException{
/* Initialise NucleotideModel part of object */
super();
/* Initialise Felsenstein 1984 specific part of object */
params = new double[alphabet.length];
oldparams = new double[alphabet.length];
/* Set all frequencies to 1/4 */
for (int i = 0; i < alphabet.length - 1; i++)
params[i] = 1.0 / (alphabet.length);
/* Set all rate ratios to 1 */
params[alphabet.length - 1] = 1.0;
/* Set diagonalising matrices and equilibrium frequencies */
setDiagonal();
}
void setDiagonal(){
/* Set equilibrium frequencies */
e[alphabet.length - 1] = 1.0;
for (int i = 0; i < alphabet.length - 1; i++){
e[i] = params[i];
e[alphabet.length - 1] -= params[i];
}
/* Set diagonal matrix */
d[0] = 0;
d[1] = -1;
d[2] = d[3] = -1 - params[params.length - 1];
/* Set v matrix */
for (int i = 0; i < alphabet.length; i++){
v[i][0] = 1;
if (i < 2){
v[i][1] = -(e[2] + e[3]) / (e[0] + e[1]);
v[i][2] = (i == 0 ? -e[1]/e[0] : 1);
v[i][3] = 0;
}
else{
v[i][1] = 1;
v[i][2] = 0;
v[i][3] = (i == 2 ? -e[3]/e[2] : 1);
}
}
/* Set w matrix */
for (int i = 0; i < alphabet.length; i++){
w[0][i] = e[i];
if (i < 2){
w[1][i] = -e[i];
w[2][i] = (i == 0 ? -1 : 1) * e[0] / (e[0] + e[1]);
w[3][i] = 0;
}
else{
w[1][i] = e[i] * (e[0] + e[1]) / (e[2] + e[3]);
w[2][i] = 0;
w[3][i] = (i == 2 ? -1 : 1) * e[2] / (e[2] + e[3]);
}
}
}
/**
* Prints the parameters of the model
*/
public String print(){
return "A\t"+e[0]+"\tC\t"+e[1]+"\tG\t"+e[2]+"\tT\t"+e[3]+"\tTs/Tv\t"+params[params.length - 1];
}
/**
* This function implements a proposal for new parameter values.
* Returns with the logarithm of the Metropolis-Hastings ratio.
*/
@Override
public double sampleParameter() {
double x;
if (Utils.generator.nextInt(alphabet.length) != 0){
/* Resample frequency parameter */
x = NucleotideModelUtils.sampleFrequencies(e, span / 2.0);
/* Save current parameters as old parameters, store new
* frequency parameters, and ensure frequencies sum to one.
*/
e[alphabet.length - 1] = 1.0;
for (int i = 0; i < params.length; i++){
oldparams[i] = params[i];
if (i < alphabet.length - 1){
params[i] = e[i];
e[alphabet.length - 1] -= e[i];
}
}
}
else{
/* Resample rate ratio parameter */
double r[] = new double[1];
r[0] = params[params.length - 1];
x = NucleotideModelUtils.sampleRates(r, span / 2.0);
oldparams[params.length - 1] = params[params.length - 1];
params[params.length - 1] = r[0];
}
setDiagonal();
return x;
}
}