/*
* DecomposedMatrix.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.inference.model;
import dr.xml.*;
/**
* @author Marc A. Suchard
*/
public class DecomposedMatrix extends MatrixParameter {
public static final String DIM = "dim";
public static final String MATRIX_PARAMETER = "decomposedMatrix";
public DecomposedMatrix(String name) {
super(name);
}
public DecomposedMatrix(String name, int dim, Parameter parameter) {
super(name);
this.dim = dim;
this.decomposition = parameter;
matrix = new double[dim][dim];
savedMatrix = new double[dim][dim];
composeMatrix();
addParameter(parameter);
}
public void parameterChangedEvent(Parameter parameter, int index) {
compositionKnown = false;
// System.err.println("called");
fireParameterChangedEvent();
}
void composeMatrix() {
// L_{ij} = index[i]+j
// M_{ij} = \sum_k L_{ik} L_{jk}
double[] values = decomposition.getParameterValues();
for (int i = 0; i < dim; i++) {
for (int j = i; j < dim; j++) {
matrix[i][j] = 0.0;
for (int k = 0; k <= i; k++)
matrix[i][j] += values[index[i] + k] * values[index[j] + k];
matrix[j][i] = matrix[i][j];
}
}
compositionKnown = true;
}
public int getDimension() {
return dim * dim;
}
protected void storeValues() {
super.storeValues();
for (int i = 0; i < dim; i++) {
System.arraycopy(matrix[i], 0, savedMatrix[i], 0, dim);
}
}
public double getParameterValue(int index) {
int x = index / dim;
int y = index - x * dim;
return matrix[x][y];
}
protected void restoreValues() {
super.restoreValues();
for (int i = 0; i < dim; i++) {
System.arraycopy(savedMatrix[i], 0, matrix[i], 0, dim);
}
}
public double getParameterValue(int row, int col) {
// System.err.println("row-col");
if (!compositionKnown)
composeMatrix();
return matrix[row][col];
}
public double[][] getParameterAsMatrix() {
// System.err.println("as-matrix");
if (!compositionKnown)
composeMatrix();
return matrix;
}
public int getColumnDimension() {
return dim;
}
public int getRowDimension() {
return dim;
}
public static XMLObjectParser PARSER = new AbstractXMLObjectParser() {
public String getParserName() {
return MATRIX_PARAMETER;
}
public Object parseXMLObject(XMLObject xo) throws XMLParseException {
Parameter parameter = (Parameter) xo.getChild(Parameter.class);
int dim = xo.getIntegerAttribute(DIM);
if (dim * (dim + 1) / 2 != parameter.getDimension())
throw new XMLParseException("Dim attribute and parameter dimension do not match");
return new DecomposedMatrix(MATRIX_PARAMETER, dim, parameter);
}
//************************************************************************
// AbstractXMLObjectParser implementation
//************************************************************************
public String getParserDescription() {
return "A diagonal matrix parameter constructed from its diagonals.";
}
public XMLSyntaxRule[] getSyntaxRules() {
return rules;
}
private XMLSyntaxRule[] rules = new XMLSyntaxRule[]{
new ElementRule(Parameter.class),
AttributeRule.newIntegerArrayRule(DIM, false)
};
public Class getReturnType() {
return DecomposedMatrix.class;
}
};
private boolean compositionKnown = false;
private Parameter decomposition;
private int dim;
private double[][] matrix;
private double[][] savedMatrix;
private static int[] index = {0, 1, 3, 6, 10, 15, 21, 28, 36};
}