001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.ml.timeseries.series; 031 032import java.io.IOException; 033import java.io.PrintWriter; 034import java.util.Arrays; 035import java.util.Collection; 036import java.util.Iterator; 037import java.util.Scanner; 038 039import org.openimaj.io.ReadWriteableASCII; 040import org.openimaj.ml.timeseries.TimeSeries; 041import org.openimaj.ml.timeseries.TimeSeriesArithmaticOperator; 042import org.openimaj.ml.timeseries.collection.TimeSeriesCollectionAssignable; 043import org.openimaj.util.pair.IndependentPair; 044 045/** 046 * @author Sina Samangooei (ss@ecs.soton.ac.uk) 047 * 048 */ 049public class DoubleTimeSeries extends TimeSeries<double[],Double,DoubleTimeSeries> 050 implements 051 TimeSeriesArithmaticOperator<Double, DoubleTimeSeries>, 052 ReadWriteableASCII, 053 TimeSeriesCollectionAssignable<Double, DoubleTimeSeries>, 054 DoubleTimeSeriesProvider 055{ 056 057 private long[] times; 058 private double[] data; 059 int size = 0; 060 061 /** 062 * Convenience constructor, makes a time series with empty data of a given size 063 * @param i 064 */ 065 public DoubleTimeSeries(int i) { 066 this.times = new long[i]; 067 this.data = new double[i]; 068 size = i; 069 } 070 /** 071 * Sets the times and data arrays backing this class 0 length 072 */ 073 public DoubleTimeSeries() { 074 this.times = new long[0]; 075 this.data = new double[0]; 076 size = 0; 077 } 078 /** 079 * 080 * @param times 081 * @param data 082 */ 083 public DoubleTimeSeries(long[] times, double[] data) { 084 this.times = times; 085 this.data = data; 086 size = this.data.length; 087 } 088 private int[] findStartEnd(long time, int nbefore, int nafter){ 089 int index = Arrays.binarySearch(times, time); 090 int fixed = index < 0 ? -1 * (index + 1) : index; 091 int start = 0; 092 int end = times.length - 1; 093 094 start = fixed- nbefore; 095 // couldn't find it 096 if(index < 0){ 097 end = fixed + nafter; 098 } 099 // could 100 else{ 101 end = fixed + nafter + 1; 102 } 103 if(start < 0) start= 0; 104 if(end > times.length) end = times.length; 105 return new int[]{start,end}; 106 } 107 @Override 108 public DoubleTimeSeries get(long time, int nbefore, int nafter) { 109 if(nbefore < 0 || nafter < 0) 110 { 111 return new DoubleTimeSeries(); 112 } 113 int[] startend = findStartEnd(time, nbefore, nafter); 114 double[] dataoutput = new double[startend[1] - startend[0]]; 115 System.arraycopy(this.data, startend[0], dataoutput, 0, dataoutput.length); 116 long[] timeoutput = new long[startend[1] - startend[0]]; 117 System.arraycopy(this.times, startend[0], timeoutput, 0, timeoutput.length); 118 DoubleTimeSeries output = newInstance(timeoutput,dataoutput); 119 return output; 120 } 121 122 @Override 123 public DoubleTimeSeries get(long time, int nbefore, int nafter, DoubleTimeSeries output) { 124 int[] startend = findStartEnd(time, nbefore, nafter); 125 System.arraycopy(this.data, startend[0], output.data, 0, startend[1]-startend[0]); 126 System.arraycopy(this.times, startend[0], output.times, 0, startend[1]-startend[0]); 127 output.size = startend[1]-startend[0]; 128 return output; 129 } 130 131 @Override 132 public DoubleTimeSeries get(long time, long threshbefore, long threshafter) { 133 if(threshafter < 0 || threshbefore < 0){ 134 return new DoubleTimeSeries(); 135 } 136 int[] startend = findStartEnd(time, 0, 0); 137 int start = startend[0]; 138 int end = start; 139 // Find the index range 140 while(start > 0 && times[start-1] >= time - threshbefore) start--; 141 while(end < times.length && times[end] <= time + threshafter) end++; 142 143 double[] dataoutput = new double[end - start]; 144 System.arraycopy(this.data, start, dataoutput, 0, dataoutput.length); 145 long[] timeoutput = new long[end - start]; 146 System.arraycopy(this.times, start, timeoutput, 0, timeoutput.length); 147 DoubleTimeSeries output = newInstance(timeoutput,dataoutput); 148 return output; 149 } 150 151 @Override 152 public DoubleTimeSeries get(long start, long end) { 153 return get(start,0,end-start); 154 } 155 156 private DoubleTimeSeries newInstance(long[] timeoutput, double[] dataoutput) { 157 DoubleTimeSeries output = newInstance(); 158 output.set(timeoutput, dataoutput); 159 return output; 160 } 161 @Override 162 public void set(long[] times, double[] data) { 163 this.times = times; 164 this.data = data; 165 this.size = data.length; 166 } 167 @Override 168 public long[] getTimes() { 169 return this.times; 170 } 171 @Override 172 public double[] getData() { 173 return this.data; 174 } 175 @Override 176 public DoubleTimeSeries newInstance() { 177 return new DoubleTimeSeries(); 178 } 179 180 @Override 181 public int size() { 182 return size; 183 } 184 @Override 185 public void internalAssign(DoubleTimeSeries interpolate) { 186 this.data = Arrays.copyOf(interpolate.data, interpolate.data.length); 187 this.times = Arrays.copyOf(interpolate.times, interpolate.times.length); 188 this.size = interpolate.size(); 189 } 190 @Override 191 public String toString() { 192 StringBuffer sb = new StringBuffer(); 193 String lf = "%d => %.5f\n"; 194 for (int i = 0; i < this.size(); i++) { 195 long time = this.times[i]; 196 double data = this.data[i]; 197 sb.append(String.format(lf, time,data)); 198 } 199 return sb.toString(); 200 } 201 @Override 202 public Iterator<IndependentPair<Long, Double>> iterator() { 203 return new Iterator<IndependentPair<Long,Double>>() { 204 int index = 0; 205 @Override 206 public boolean hasNext() { 207 return index < DoubleTimeSeries.this.size; 208 } 209 210 @Override 211 public IndependentPair<Long, Double> next() { 212 IndependentPair<Long, Double> toret = IndependentPair.pair(DoubleTimeSeries.this.times[index],DoubleTimeSeries.this.data[index]); 213 index++; 214 return toret; 215 } 216 217 @Override 218 public void remove() { 219 } 220 }; 221 } 222 @Override 223 public void readASCII(Scanner in) throws IOException { 224 this.size = in.nextInt(); 225 this.data = new double[size]; 226 this.times = new long[size]; 227 for (int i = 0; i < size; i++) { 228 times[i] = in.nextLong(); 229 data[i] = in.nextDouble(); 230 } 231 232 } 233 @Override 234 public String asciiHeader() { 235 return ""; 236 } 237 @Override 238 public void writeASCII(PrintWriter out) throws IOException { 239 out.print(this.size() + " "); 240 for (IndependentPair<Long, Double> timedouble: this) { 241 out.print(timedouble.firstObject() + " " + timedouble.secondObject() + " "); 242 } 243 } 244 @Override 245 public DoubleTimeSeries newInstance(Collection<Long> time,Collection<Double> data) { 246 DoubleTimeSeries d = new DoubleTimeSeries(); 247 d.internalAssign(time, data); 248 return d; 249 } 250 @Override 251 public void internalAssign(Collection<Long> time, Collection<Double> data) { 252 this.times = new long[time.size()]; 253 this.data = new double[time.size()]; 254 this.size = data.size(); 255 int i = 0; 256 for (Long l : time) this.times[i++] = l; 257 i = 0; 258 for (Double d : data) this.data[i++] = d; 259 } 260 @Override 261 public void internalAssign(long[] times, double[] data) { 262 this.times = times; 263 this.data = data; 264 this.size = times.length; 265 266 } 267 @Override 268 public Double zero() { 269 return 0d; 270 } 271 @Override 272 public Double sum() { 273 double s = 0; 274 for (int i = 0; i < this.data.length; i++) { 275 s += this.data[i]; 276 } 277 return s; 278 } 279 @Override 280 public DoubleTimeSeries doubleTimeSeries() { 281 return this; 282 } 283}