package statalign.model.subst;
import java.awt.*;
import java.util.Arrays;
import statalign.model.score.*;
import statalign.io.*;
/**
*
* Superclass of the substitution models.
*
* @author miklos, novak
*
*/
public abstract class SubstitutionModel{
/**
* The rate matrix must be diagonalized and represented in a
* <b>v d w</b> product, where <b>d</b> is a diagonal matrix
*/
public double[][] v;
/**
* The rate matrix must be diagonalized and represented in a
* <b>v d w</b> product, where <b>d</b> is a diagonal matrix
*/
public double[][] w;
/**
* The rate matrix must be diagonalized and represented in a
* <b>v d w</b> product, where <b>d</b> is a diagonal matrix.
* Only the diagonal elements must be put into the one dimensional array <b>d</b>.
*/
public double[] d;
/**
* This array tells the equilibrium distribution
*/
public double[] e;
/**
* This array contains the potential characters of the alphabet.
*/
public char[] alphabet;
/**
* Model parameters.
*/
public double params[];
/**
* Tells whether your plugin is a nucleotide or protein model (or something else)
* when declared with the same name and type.
* Affects grouping of models in the menu.
*/
public static String type;
/**
* Sets the name of the model plugin that will appear in the menu when declared
* with the same name and type.
*/
public static String menuName;
/**
* This scoring scheme is used for constructing an
* initial tree.
*/
public SubstitutionScore attachedScoringScheme;
/** Determines the span for proposing new parameters. Updated automatically during MCMC. */
protected double span = 0.1;
public void updateSpan(double newSpan) { span = newSpan; }
/**
*
* If a model cannot accept the currently loaded sequences
* (for example, because the sequences contains a character that is not part of the model)
* then it returns a negative number. Otherwise it returns a double value between 0 and 1,
* the better likes the model the sequences the greater the return number is.
*
* @param r raw sequences
* @return the value telling how well the substitution model likes the sequences.
*/
public abstract double acceptable(RawSequences r);
/**
* Updates externally stored transition matrix using current values of v, w, d, e and current
* edge length. Must always be called in the form m = updateTransitionMatrix(m, len) where m
* can be null as well.
* @param transitionMatrix reference to matrix to store results, null to create new
* @param edgeLength evolutionary time
* @return updated (or newly created) transition matrix
*/
public double[][] updateTransitionMatrix(double[][] transitionMatrix, double edgeLength){
int i, j, k;
int n = d.length;
if(transitionMatrix == null)
transitionMatrix = new double[n][n];
else {
for(i = 0; i < transitionMatrix.length; i++)
Arrays.fill(transitionMatrix[i], 0.0);
}
double exp_dtk;
for(k = 0; k < n; k++){
exp_dtk = Math.exp(d[k]*edgeLength);
for(i = 0; i < n; i++){
for(j = 0; j < n; j++){
transitionMatrix[i][j] += v[i][k] * exp_dtk * w[k][j];
}
}
}
return transitionMatrix;
}
/**
* Abstract method to sample a new model parameter and update v,w,d,e accordingly.
*
* @return log(fwd proposal probability/bwd proposal probability) [i.e. inverse Hastings ratio]
*/
public abstract double sampleParameter();
/**
* Restores state just before the call of sampleParameter
*/
public abstract void restoreParameter();
/**
* Represents model state as a String (usually parameter values concatenated)
*
* @return the resulting String
*/
public abstract String print();
/**
* Returns the colour associated with the character. This colour will be
* the background colour of the character in the printed alignments.
*
* @param c character whose background colour is to be returned
*/
public abstract Color getColor(char c);
public abstract char mostLikely(double[] seq);
/**
* Retrieves the static field <code>type</code> of the class of the object the
* method is called on.
*
* See <code>getType(Class cl)</code> for details.
*/
public String getType() {
return getType(getClass());
}
/**
* Retrieves the static field <code>type</code> of a SubstitutionModel plug-in class.
* In the class it must be declared <code>public static String</code>.
* Searches the class hierarchy upwards until a class with the field declared is found.
*
* @param cl class extending <code>SubstitutionModel</code>
* @return value of the static field <code>type</code> or "unknown" if the field
* is null or empty
*/
@SuppressWarnings("unchecked")
public static String getType(Class<? extends SubstitutionModel> cl) {
String type = null;
while(true) {
try {
type = (String)cl.getField("type").get(null);
break;
} catch (Exception e) {}
cl = (Class<? extends SubstitutionModel>)cl.getSuperclass();
}
if(type == null || type.equals(""))
type = "unknown";
return type;
}
/**
* Retrieves the static field <code>menuName</code> of the class of the object the
* method is called on.
*
* See <code>getMenuName(Class cl)</code> for details.
*/
public String getMenuName() {
return getMenuName(getClass());
}
/**
* Retrieves <code>menuName</code> static field of a SubstitutionModel plug-in class.
* In the class it must be declared <code>public static String</code>.
*
* @param cl class extending <code>SubstitutionModel</code>
* @return value of the static field <code>menuName</code> or the simple name of
* <code>cl</code> if the field doesn't exist or is null
*/
public static String getMenuName(Class<? extends SubstitutionModel> cl) {
String name = null;
try {
name = (String)cl.getField("menuName").get(null);
} catch (Exception e) {}
if(name == null)
name = cl.getSimpleName();
return name;
}
/**
* Returns the prior for the substitution parameters.
* By default the prior is uniform and this function returns 1.
* @return prior for the parameters of the substitution model.
*/
public double getPrior(){
return 1;
}
}