/*
* GeoSpatialCollectionModel.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.geo;
import dr.inference.model.AbstractModelLikelihood;
import dr.inference.model.Model;
import dr.inference.model.Parameter;
import dr.inference.model.Variable;
import java.util.List;
/**
* @author Marc A. Suchard
* <p/>
* Provides a GeoSpatialDistribution over multiple points in multiple polygon.
* Uses AbstractModelLikelihood to cache 'contains' to reduce recalculations
* when only a single point is updated
*/
public class GeoSpatialCollectionModel extends AbstractModelLikelihood {
public GeoSpatialCollectionModel(String name, Parameter points,
List<GeoSpatialDistribution> geoSpatialDistributions,
boolean isIntersection) {
super(name);
this.points = points;
this.geoSpatialDistributions = geoSpatialDistributions;
dim = points.getDimension() / GeoSpatialDistribution.dimPoint;
cachedPointLogLikelihood = new double[dim];
storedCachedPointLogLikelihood = new double[dim];
validPointLogLikelihood = new boolean[dim];
storedValidPointLogLikelihood = new boolean[dim];
likelihoodKnown = false;
addVariable(points);
this.isIntersection = isIntersection;
}
protected void handleModelChangedEvent(Model model, Object object, int index) {
// No submodels; do nothing
}
protected void handleVariableChangedEvent(Variable variable, int index, Parameter.ChangeType type) {
// Mark appropriate dim as invalid
validPointLogLikelihood[index / GeoSpatialDistribution.dimPoint] = false;
likelihoodKnown = false;
}
protected void storeState() {
System.arraycopy(cachedPointLogLikelihood, 0, storedCachedPointLogLikelihood, 0, dim);
System.arraycopy(validPointLogLikelihood, 0, storedValidPointLogLikelihood, 0, dim);
storedLikelihoodKnown = likelihoodKnown;
storedLogLikelihood = logLikelihood;
}
protected void restoreState() {
double[] tmp1 = cachedPointLogLikelihood;
cachedPointLogLikelihood = storedCachedPointLogLikelihood;
storedCachedPointLogLikelihood = tmp1;
boolean[] tmp2 = validPointLogLikelihood;
validPointLogLikelihood = storedValidPointLogLikelihood;
storedValidPointLogLikelihood = tmp2;
likelihoodKnown = storedLikelihoodKnown;
logLikelihood = storedLogLikelihood;
}
protected void acceptState() {
}
public Model getModel() {
return this;
}
public double getLogLikelihood() {
if (likelihoodKnown)
return logLikelihood;
logLikelihood = 0.0;
final double[] point = new double[GeoSpatialDistribution.dimPoint];
for (int i = 0; i < dim; i++) {
if (!validPointLogLikelihood[i]) {
final int offset = i * GeoSpatialDistribution.dimPoint;
for (int j = 0; j < GeoSpatialDistribution.dimPoint; j++)
point[j] = points.getParameterValue(offset + j);
double pointLogLikelihood = 0;
for (GeoSpatialDistribution distribution : geoSpatialDistributions) {
//if we consider the union of polygons and the point must be inside, than it is good enough that the point is in one polygon
//so we look for a polygon that does not yield -inf
if (!isIntersection && !distribution.getOutside()) {
final double logPdf = distribution.logPdf(point);
if (logPdf != Double.NEGATIVE_INFINITY) {
pointLogLikelihood = logPdf;
break;
} else {
pointLogLikelihood = logPdf;
}
} else {
// Below is for intersections (or unions of complements)
pointLogLikelihood += distribution.logPdf(point);
if (pointLogLikelihood == Double.NEGATIVE_INFINITY)
break; // No need to finish
}
}
cachedPointLogLikelihood[i] = pointLogLikelihood;
validPointLogLikelihood[i] = true;
}
logLikelihood += cachedPointLogLikelihood[i];
if (logLikelihood == Double.NEGATIVE_INFINITY)
break; // No need to finish
}
likelihoodKnown = true;
return logLikelihood;
}
public void makeDirty() {
likelihoodKnown = false;
for (int i = 0; i < dim; i++)
validPointLogLikelihood[i] = false;
}
public Parameter getParameter() {
return points;
}
private Parameter points;
private List<GeoSpatialDistribution> geoSpatialDistributions;
private int dim;
private double[] cachedPointLogLikelihood;
private double[] storedCachedPointLogLikelihood;
private boolean likelihoodKnown;
private boolean storedLikelihoodKnown;
private double logLikelihood;
private double storedLogLikelihood;
private boolean[] validPointLogLikelihood;
private boolean[] storedValidPointLogLikelihood;
private final boolean isIntersection;
}