/*
* Intervals.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.evolution.coalescent;
import dr.evolution.util.Units;
import java.util.Arrays;
/**
* A concrete class for a set of coalescent intervals.
*
* @author Andrew Rambaut
* @author Alexei Drummond
* @version $Id: Intervals.java,v 1.19 2005/09/21 18:47:58 gerton Exp $
*/
public class Intervals implements IntervalList {
public Intervals(int maxEventCount) {
events = new Event[maxEventCount];
for (int i = 0; i < maxEventCount; i++) {
events[i] = new Event();
}
eventCount = 0;
sampleCount = 0;
intervals = new double[maxEventCount - 1];
intervalTypes = new IntervalType[maxEventCount - 1];
lineageCounts = new int[maxEventCount - 1];
intervalsKnown = false;
}
public void copyIntervals(Intervals source) {
intervalsKnown = source.intervalsKnown;
eventCount = source.eventCount;
sampleCount = source.sampleCount;
//don't copy the actual events..
/*
for (int i = 0; i < events.length; i++) {
events[i].time = source.events[i].time;
events[i].type = source.events[i].type;
}*/
if (intervalsKnown) {
System.arraycopy(source.intervals, 0, intervals, 0, intervals.length);
System.arraycopy(source.intervalTypes, 0, intervalTypes, 0, intervals.length);
System.arraycopy(source.lineageCounts, 0, lineageCounts, 0, intervals.length);
}
}
public void resetEvents() {
intervalsKnown = false;
eventCount = 0;
sampleCount = 0;
}
public void addSampleEvent(double time) {
events[eventCount].time = time;
events[eventCount].type = IntervalType.SAMPLE;
eventCount++;
sampleCount++;
intervalsKnown = false;
}
public void addCoalescentEvent(double time) {
events[eventCount].time = time;
events[eventCount].type = IntervalType.COALESCENT;
eventCount++;
intervalsKnown = false;
}
public void addMigrationEvent(double time, int destination) {
events[eventCount].time = time;
events[eventCount].type = IntervalType.MIGRATION;
events[eventCount].info = destination;
eventCount++;
intervalsKnown = false;
}
public void addNothingEvent(double time) {
events[eventCount].time = time;
events[eventCount].type = IntervalType.NOTHING;
eventCount++;
intervalsKnown = false;
}
public int getSampleCount() {
return sampleCount;
}
public int getIntervalCount() {
if (!intervalsKnown) calculateIntervals();
return intervalCount;
}
public double getInterval(int i) {
if (!intervalsKnown) calculateIntervals();
return intervals[i];
}
public int getLineageCount(int i) {
if (!intervalsKnown) calculateIntervals();
return lineageCounts[i];
}
public int getCoalescentEvents(int i) {
if (!intervalsKnown) calculateIntervals();
if (i < intervalCount - 1) {
return lineageCounts[i] - lineageCounts[i + 1];
} else {
return lineageCounts[i] - 1;
}
}
public IntervalType getIntervalType(int i) {
if (!intervalsKnown) calculateIntervals();
return intervalTypes[i];
}
public double getTotalDuration() {
if (!intervalsKnown) calculateIntervals();
return events[eventCount - 1].time;
}
public boolean isBinaryCoalescent() {
return true;
}
public boolean isCoalescentOnly() {
return true;
}
private void calculateIntervals() {
if (eventCount < 2) {
throw new IllegalArgumentException("Too few events to construct intervals");
}
Arrays.sort(events, 0, eventCount);
if (events[0].type != IntervalType.SAMPLE) {
throw new IllegalArgumentException("First event is not a sample event");
}
intervalCount = eventCount - 1;
double lastTime = events[0].time;
int lineages = 1;
for (int i = 1; i < eventCount; i++) {
intervals[i - 1] = events[i].time - lastTime;
intervalTypes[i - 1] = events[i].type;
lineageCounts[i - 1] = lineages;
if (events[i].type == IntervalType.SAMPLE) {
lineages++;
} else if (events[i].type == IntervalType.COALESCENT) {
lineages--;
}
lastTime = events[i].time;
}
intervalsKnown = true;
}
private Units.Type units = Units.Type.GENERATIONS;
public final Units.Type getUnits() {
return units;
}
public final void setUnits(Type units) {
this.units = units;
}
private class Event implements Comparable {
public int compareTo(Object o) {
double t = ((Event) o).time;
if (t < time) {
return 1;
} else if (t > time) {
return -1;
} else {
// events are at exact same time so sort by type
return type.compareTo(((Event) o).type);
}
}
/**
* The type of event
*/
IntervalType type;
/**
* The time of the event
*/
double time;
/**
* Some extra information for the event (e.g., destination of a migration)
*/
int info;
}
private Event[] events;
private int eventCount;
private int sampleCount;
private boolean intervalsKnown = false;
private double[] intervals;
private int[] lineageCounts;
private IntervalType[] intervalTypes;
//private int[] destinations;
private int intervalCount = 0;
}