org.opentripplanner.profile.TimeRange Maven / Gradle / Ivy
package org.opentripplanner.profile;
import com.beust.jcommander.internal.Maps;
import org.opentripplanner.model.Stop;
import java.util.Iterator;
import java.util.Map;
public class TimeRange {
public int min, max, avg, n;
/** Construct a TimeRange where all fields are zero. */
public TimeRange() { };
/** Construct a TimeRange for a single value. */
public TimeRange(int t) {
this.min = t;
this.max = t;
this.avg = t;
n = 1;
}
/** Return true if the time range was updated, false if it remained the same. */
// TODO does comparing averages lead to an endless-improvement loop situation?
public boolean mergeIn (TimeRange other) {
if (other.min < this.min || other.max < this.max || other.avg < this.avg) {
// the other range is better in at least one way, combine it into this one
if (other.min < this.min && other.max < this.max && other.avg < this.avg) {
// the other range completely dominates the existing one, replacing it entirely
this.min = other.min;
this.max = other.max;
this.avg = other.avg;
this.n = other.n;
return true;
}
if (other.min < this.min) this.min = other.min;
if (other.max < this.max) this.max = other.max; // Yes, we want the minimum upper bound.
// Watch out for overflow here.
// double newAverage = this.avg * (double) this.n + other.avg * (double) other.n;
// this.n += other.n;
// newAverage /= this.n;
// this.avg = (int) newAverage;
// This assumes all the mixed distributions are symmetric, which they are not. But just to get some coherent value...
this.avg = (int) (((double) this.min + (double) this.max) / 2.0d);
checkCoherent();
return true; // We know at least one field was updated.
} else {
// the other range is worse in every way, ignore it
return false;
}
}
/** Return a copy of this TimeRange that is translated forward in time by t seconds. */
public TimeRange shift (int t) {
TimeRange ret = new TimeRange();
ret.min = this.min + t;
ret.max = this.max + t;
ret.avg = this.avg + t;
ret.n = this.n;
return ret;
}
/** Return a copy of this TimeRange that includes a uniformly distributed wait from zero to t seconds. */
public TimeRange wait (int t) {
TimeRange ret = new TimeRange();
ret.min = this.min;
ret.max = this.max + t;
ret.avg = this.avg + t/2;
ret.n = this.n;
return ret;
}
/** Keeps one TimeRange per TransitStop that has been reached. */
public static class Tracker implements Iterable {
Map ranges = Maps.newHashMap();
/** Set the travel time to a specific transit stop to exactly t seconds, overwriting any existing value. */
public void set (Stop stop, int t) {
ranges.put(stop, new TimeRange(t));
}
/** Get the existing TimeRange for the specified stop, or NULL if none is defined. */
public TimeRange get (Stop stop) {
return ranges.get(stop);
}
/** Return true if the time range at the given stop was updated. */
public boolean add (Stop stop, TimeRange newRange) {
TimeRange existingRange = ranges.get(stop);
if (existingRange == null) {
ranges.put(stop, newRange);
return true;
}
return existingRange.mergeIn(newRange);
}
@Override
public Iterator iterator() {
return ranges.keySet().iterator();
}
}
public void checkCoherent() {
if (avg < 0) {
System.out.printf ("avg is negative: %d \n", avg);
}
if (! (min <= avg && avg <= max)) {
System.out.printf("incoherent: min %d avg %d max %d \n", min, avg, max);
}
}
}