/* * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. * * Created on 20.04.2008 */ package net.finmath.time; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.Set; /** * This class represents a set of discrete points in time. * <br> * It handles the mapping from time indices to time points and back. * It uses a time tick size ("quantum"). This is to make comparison of times safe. * The default tick size is 1.0 / (365.0 * 24.0) (which corresponds to one hour if 1.0 is a non-leap-year): * Times are rounded to the nearest multiple of 1.0 / (365.0 * 24.0). * * This property can be configured via a System.setProperty("net.finmath.functions.TimeDiscretization.timeTickSize"). * * Objects of this class are immutable. * * @author Christian Fries * @version 1.6 */ public class TimeDiscretization implements Serializable, TimeDiscretizationInterface { private static final long serialVersionUID = 6880668325019167781L; private final static double timeTickSizeDefault = Double.parseDouble(System.getProperty("net.finmath.functions.TimeDiscretization.timeTickSize", new Double(1.0 / (365.0 * 24.0)).toString()));; private final double[] timeDiscretization; private final double timeTickSize = timeTickSizeDefault; public enum ShortPeriodLocation { SHORT_PERIOD_AT_START, SHORT_PERIOD_AT_END } /** * Constructs a time discretization from a given set of doubles. * The given array does not need to be sorted. * * @param times Given array or arguments list of discretization points. */ public TimeDiscretization(double... times) { super(); this.timeDiscretization = times.clone(); java.util.Arrays.sort(this.timeDiscretization); } /** * Constructs a time discretization from a given set of Doubles. * The given array does not need to be sorted. * * @param times Given array or arguments list of discretization points. */ public TimeDiscretization(Double[] times) { super(); this.timeDiscretization = new double[times.length]; for(int timeIndex=0; timeIndex<timeDiscretization.length; timeIndex++) this.timeDiscretization[timeIndex] = roundToTimeTickSize(times[timeIndex]); java.util.Arrays.sort(this.timeDiscretization); } /** * Constructs a time discretization from a given ArrayList of Doubles. * The given list does not need to be sorted. * * @param timeDiscretization Given ArrayList of discretization points */ public TimeDiscretization(ArrayList<Double> timeDiscretization) { super(); this.timeDiscretization = new double[timeDiscretization.size()]; for(int timeIndex=0; timeIndex<timeDiscretization.size(); timeIndex++) this.timeDiscretization[timeIndex] = roundToTimeTickSize(timeDiscretization.get(timeIndex)); java.util.Arrays.sort(this.timeDiscretization); } /** * Constructs a time discretization from a given Set of Doubles. * * @param times Given Set of discretization points */ public TimeDiscretization(Set<Double> times) { super(); this.timeDiscretization = new double[times.size()]; Iterator<Double> time = times.iterator(); for(int timeIndex=0; timeIndex<timeDiscretization.length; timeIndex++) this.timeDiscretization[timeIndex] = roundToTimeTickSize(time.next()); java.util.Arrays.sort(this.timeDiscretization); } /** * Constructs an equi-distant time discretization with points timeDiscretization[i] being * <code>for(i=0; i ≤ timeSteps; i++) timeDiscretization[i] = initial + i * deltaT;</code> * * @param initial First discretization point. * @param numberOfTimeSteps Number of time steps. * @param deltaT Time step size. */ public TimeDiscretization(double initial, int numberOfTimeSteps, double deltaT) { super(); timeDiscretization = new double[numberOfTimeSteps+1]; for(int timeIndex=0; timeIndex<timeDiscretization.length; timeIndex++) timeDiscretization[timeIndex] = roundToTimeTickSize(initial + timeIndex * deltaT); } /** * Constructs an equi-distant time discretization with stub periods at start or end. * * @param initial First discretization point. * @param last Last time steps. * @param deltaT Time step size. * @param shortPeriodLocation Placement of the stub period. */ public TimeDiscretization(double initial, double last, double deltaT, ShortPeriodLocation shortPeriodLocation) { super(); int numberOfTimeSteps = (int)((last-initial)/ deltaT + 0.5); // Adjust for short period, if any if(roundToTimeTickSize(initial + numberOfTimeSteps * deltaT) < roundToTimeTickSize(last)) numberOfTimeSteps++; timeDiscretization = new double[numberOfTimeSteps+1]; if(shortPeriodLocation == ShortPeriodLocation.SHORT_PERIOD_AT_END) { for(int timeIndex=0; timeIndex<timeDiscretization.length; timeIndex++) timeDiscretization[timeIndex] = roundToTimeTickSize(initial + timeIndex * deltaT); timeDiscretization[timeDiscretization.length-1] = last; } else { for(int timeIndex=0; timeIndex<timeDiscretization.length; timeIndex++) timeDiscretization[timeIndex] = roundToTimeTickSize(last - (numberOfTimeSteps-timeIndex) * deltaT); timeDiscretization[0] = initial; } } @Override public int getNumberOfTimes() { return timeDiscretization.length; } @Override public int getNumberOfTimeSteps() { return timeDiscretization.length-1; } @Override public double getTime(int timeIndex) { return timeDiscretization[timeIndex]; } @Override public double getTimeStep(int timeIndex) { return timeDiscretization[timeIndex+1]-timeDiscretization[timeIndex]; } @Override public int getTimeIndex(double time) { int index = java.util.Arrays.binarySearch(timeDiscretization,roundToTimeTickSize(time)); return index; } @Override public int getTimeIndexNearestLessOrEqual(double time) { int index = java.util.Arrays.binarySearch(timeDiscretization,roundToTimeTickSize(time)); if(index < 0) index = -index-2; return index; } @Override public int getTimeIndexNearestGreaterOrEqual(double time) { int index = java.util.Arrays.binarySearch(timeDiscretization,time); if(index < 0) index = -index-1; return index; } @Override public double[] getAsDoubleArray() { // Note: This is a deep copy return timeDiscretization.clone(); } @Override public ArrayList<Double> getAsArrayList() { ArrayList<Double> times = new ArrayList<Double>(timeDiscretization.length); for (double aTimeDiscretization : timeDiscretization) times.add(aTimeDiscretization); return times; } @Override public TimeDiscretizationInterface getTimeShiftedTimeDiscretization(double timeShift) { double[] newTimeDiscretization = new double[timeDiscretization.length]; for(int timeIndex=0; timeIndex<timeDiscretization.length; timeIndex++) { newTimeDiscretization[timeIndex] = roundToTimeTickSize(timeDiscretization[timeIndex]+timeShift); } return new TimeDiscretization(newTimeDiscretization); } @Override public Iterator<Double> iterator() { return this.getAsArrayList().iterator(); } @Override public String toString() { return "TimeDiscretization [timeDiscretization=" + Arrays.toString(timeDiscretization) + ", timeTickSize=" + timeTickSize + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(timeDiscretization); long temp; temp = Double.doubleToLongBits(timeTickSize); result = prime * result + (int) (temp ^ (temp >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; TimeDiscretization other = (TimeDiscretization) obj; if (!Arrays.equals(timeDiscretization, other.timeDiscretization)) return false; if (Double.doubleToLongBits(timeTickSize) != Double.doubleToLongBits(other.timeTickSize)) return false; return true; } private double roundToTimeTickSize(double time) { return Math.rint(time/timeTickSize)*timeTickSize; } }