/*
* SparseMatrixExponential.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.math;
/**
* Created by IntelliJ IDEA.
* User: msuchard
* Date: Jul 28, 2007
* Time: 11:05:44 AM
* To change this template use File | Settings | File Templates.
*/
public class SparseMatrixExponential {
public static int maxKrylovBasisSize = 50;
public static double tolerance = 1E-7;
static {
System.loadLibrary("ExpoKit");
}
private native void executeDGEXPV(int order, int nz, int maxBasis, double time,
double[] operandVector, double[] resultVector,
double tolerance, double matrixNorm,
double[] rate, int[] indexX, int[] indexY,
double[] workspace, int lengthWorkspace,
int[] intWorkspace, int lengethIntWorkspace,
int flag
);
private int order;
private int nonZeroEntries;
private int krylovBasisSize;
private double[] workSpace;
private int[] intWorkSpace;
private int lengthWorkspace;
private int lengthIntWorkspace;
private int[] fortranIndexX;
private int[] fortranIndexY;
private double[] rate;
private double[] start;
private double[] stop;
private double norm;
int index = 0;
public SparseMatrixExponential(int order, int nonZeroEntries) {
this.order = order;
this.nonZeroEntries = nonZeroEntries;
setUpWorkspace();
}
private void setUpWorkspace() {
if (order < maxKrylovBasisSize)
krylovBasisSize = order - 10; // todo determine correct cut-off, consider Pade approximation for small order
else
krylovBasisSize = maxKrylovBasisSize - 1;
lengthIntWorkspace = krylovBasisSize + 2;
lengthWorkspace = order * (lengthIntWorkspace)
+ 5 * (lengthIntWorkspace) * (lengthIntWorkspace) + 7;
intWorkSpace = new int[lengthIntWorkspace];
workSpace = new double[lengthWorkspace];
start = new double[order];
stop = new double[order];
fortranIndexX = new int[nonZeroEntries];
fortranIndexY = new int[nonZeroEntries];
rate = new double[nonZeroEntries];
}
public void addEntry(int i, int j, double value) {
fortranIndexX[index] = i + 1;
fortranIndexY[index] = j + 1;
rate[index] = value;
index++;
}
public void setNorm(double norm) {
this.norm = norm;
}
public void calculateInfinityNorm() {
// todo
}
public double getExponentialEntry(int x, int y, double time) {
start[x] = 1.0;
int flag = 0;
executeDGEXPV(order, nonZeroEntries, krylovBasisSize, time, start, stop, tolerance, norm,
rate, fortranIndexX, fortranIndexY,
workSpace, lengthWorkspace, intWorkSpace, lengthIntWorkspace, flag
);
start[x] = 0.0; // recycle
return stop[y]; // stop gets overwritten with each call, no need to reset values
}
public String sparseRepresentation() {
StringBuffer sb = new StringBuffer();
sb.append(order + " " + nonZeroEntries + "\n");
for (int i = 0; i < nonZeroEntries; i++) {
sb.append(fortranIndexX[i]);
sb.append(" ");
sb.append(fortranIndexY[i]);
sb.append(" ");
sb.append(rate[i]);
sb.append("\n");
}
return sb.toString();
}
}