package org.opentripplanner.analyst.cluster;
import org.opentripplanner.analyst.ResultSet;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* This is a class that stores several result sets: an upper bound, a lower bound, and a central tendency.
* This is an "Envelope" in the sense that the results it contains enclose an area on a map or a chart:
* either the space between the minimum and maximum extent of an N-minute isochrone, or the space between the minimum
* and maximum accessibility curves on the cumulative access chart.
*
* @author mattwigway
*/
public class ResultEnvelope implements Serializable {
/**
* The best case/upper bound (e.g. number of jobs reachable considering the best travel times seen during the
* time window)
*/
public ResultSet bestCase;
/**
* The lower bound (e.g. number of jobs reachable considering the worst travel times seen during the time window)
*/
public ResultSet worstCase;
/**
* The average case (e.g. the number of jobs reachable on average, departing randomly within the time window)
*/
public ResultSet avgCase;
/**
* A point estimate of accessibility, in the statistical sense: a single result that serves as a representative point
* in a distribution. When we are not doing profile routing (when we are not varying the departure time or other
* characteristics such as frequency board delays or schedule pulsing) we get only a single set of travel
* times out of a search. This is only one draw out of a distribution, and we don't know how much the values
* can vary around this single example.
*
* Note that this is not a single travel time, but a single set of travel times to all targets (points/vertices).
*/
public ResultSet pointEstimate;
/**
* The spread of results (future use). This could be the standard deviation or
* interquartile range, for example.
*/
public ResultSet spread;
/**
* Is this a profile request?
* If so, upperBound and lowerBound will be defined, and pointEstimate not.
* Otherwise, only pointEstimate will be defined.
*/
public boolean profile;
/** The ID of the job of which this resultenvelope is a part */
public String jobId;
/** The ID of the feature from whence this result envelope came */
public String id;
/** The ID of the shapefile/pointset from whence this result envelope came */
public String destinationPointsetId;
public ResultSet get (Which key) {
switch (key) {
case BEST_CASE:
return this.bestCase;
case WORST_CASE:
return this.worstCase;
case POINT_ESTIMATE:
return this.pointEstimate;
case SPREAD:
return this.spread;
case AVERAGE:
return this.avgCase;
default:
throw new IllegalStateException("Invalid result type!");
}
}
public void put (Which key, ResultSet val) {
switch (key) {
case BEST_CASE:
this.bestCase = val;
break;
case WORST_CASE:
this.worstCase = val;
break;
case POINT_ESTIMATE:
this.pointEstimate = val;
break;
case SPREAD:
this.spread = val;
break;
case AVERAGE:
this.avgCase = val;
break;
}
}
/**
* Explode this result envelope into a result envelope for each contained attribute
* We do this because we need to retrieve all of the values for a particular variable quickly, in order to display the map,
* and looping over 10GB of data to do this is not tractable.
*/
public Map<String, ResultEnvelope> explode () {
Map<String, ResultEnvelope> exploded = new HashMap<String, ResultEnvelope>();
// find a non-null resultset
for (String attr : (pointEstimate != null ? pointEstimate : avgCase).histograms.keySet()) {
ResultEnvelope env = new ResultEnvelope();
for (Which which : Which.values()) {
ResultSet orig = this.get(which);
if (orig != null) {
ResultSet rs = new ResultSet();
rs.id = orig.id;
rs.histograms.put(attr, orig.histograms.get(attr));
env.put(which, rs);
env.id = this.id;
}
}
exploded.put(attr, env);
}
return exploded;
}
/**
* Build an empty result envelope.
*/
public ResultEnvelope () {
// do nothing, restore default constructor
}
public static enum Which {
BEST_CASE, WORST_CASE, POINT_ESTIMATE, SPREAD, AVERAGE;
/** Return a human readable string of this value */
public String toHumanString () {
switch (this) {
case BEST_CASE:
return "best case";
case WORST_CASE:
return "worst case";
case POINT_ESTIMATE:
return "point estimate";
case SPREAD:
return "spread";
case AVERAGE:
return "average";
default:
throw new IllegalStateException("Unknown envelope parameter");
}
}
}
}