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.collection; 031 032import java.util.ArrayList; 033import java.util.Collection; 034import java.util.HashMap; 035import java.util.HashSet; 036import java.util.Iterator; 037import java.util.Map; 038import java.util.Map.Entry; 039import java.util.Set; 040 041import org.openimaj.ml.timeseries.IncompatibleTimeSeriesException; 042import org.openimaj.ml.timeseries.TimeSeries; 043import org.openimaj.ml.timeseries.TimeSeriesSetException; 044import org.openimaj.ml.timeseries.converter.TimeSeriesConverter; 045import org.openimaj.ml.timeseries.processor.TimeSeriesProcessor; 046import org.openimaj.util.pair.IndependentPair; 047 048/** 049 * A collection of time series which share exactly the same time steps. 050 * Given that this is true, SynchronisedTimeSeriesProcessor instances can perform interesting analysis 051 * 052 * @author Sina Samangooei (ss@ecs.soton.ac.uk) 053 * @param <ALLINPUT> The collection input type 054 * @param <SINGLEINPUT> The type of a single data type 055 * @param <TIMESERIES> the type of time series returned 056 * @param <INTERNALSERIES> the type of time series held 057 * 058 */ 059public abstract class TimeSeriesCollection< 060 ALLINPUT, 061 SINGLEINPUT, 062 TIMESERIES extends TimeSeriesCollection<ALLINPUT, SINGLEINPUT,TIMESERIES,INTERNALSERIES>, 063 INTERNALSERIES extends TimeSeries<ALLINPUT,SINGLEINPUT,INTERNALSERIES> 064> extends TimeSeries< 065 Map<String,ALLINPUT>, 066 Map<String,SINGLEINPUT>, 067 TIMESERIES 068> { 069 070 protected HashMap<String, INTERNALSERIES> timeSeriesHolder; 071 072 /** 073 * initialise the underlying time series holder 074 */ 075 public TimeSeriesCollection(){ 076 this.timeSeriesHolder = new HashMap<String,INTERNALSERIES>(); 077 } 078 079 /** 080 * @param name 081 * @param series 082 * @throws IncompatibleTimeSeriesException 083 */ 084 public void addTimeSeries(String name, INTERNALSERIES series) throws IncompatibleTimeSeriesException { 085 this.timeSeriesHolder.put(name, series); 086 087 } 088 089 /** 090 * @param name the name of the series 091 * @return the series held by the name 092 */ 093 public INTERNALSERIES series(String name){ 094 return this.timeSeriesHolder.get(name); 095 } 096 097 /** 098 * @return all the time series held 099 */ 100 public Collection<INTERNALSERIES> allseries(){ 101 return this.timeSeriesHolder.values(); 102 } 103 104 105 @Override 106 public TIMESERIES get(long time, int nbefore, int nafter) { 107 TIMESERIES t = newInstance(); 108 HashMap<String, ALLINPUT> inputs = new HashMap<String,ALLINPUT>(); 109 long[] times = null; 110 for (Entry<String, INTERNALSERIES> a : this.timeSeriesHolder.entrySet()) { 111 INTERNALSERIES sub = a.getValue().get(time, nbefore, nafter); 112 times = sub.getTimes(); 113 inputs.put(a.getKey(), sub.getData()); 114 } 115 try{ 116 t.set(times, inputs); 117 } 118 catch(Exception e){ 119 e.printStackTrace(); 120 } 121 return t; 122 } 123 124 @Override 125 public Map<String, ALLINPUT> getData() { 126 Map<String, ALLINPUT> ret = new HashMap<String, ALLINPUT>(); 127 for (Entry<String, INTERNALSERIES> es : this.timeSeriesHolder.entrySet()) { 128 ret.put(es.getKey(), es.getValue().getData()); 129 } 130 131 return ret; 132 } 133 134 @Override 135 public TIMESERIES get(long start, long end) { 136 TIMESERIES t = newInstance(); 137 HashMap<String, ALLINPUT> inputs = new HashMap<String,ALLINPUT>(); 138 long[] times = null; 139 for (Entry<String, INTERNALSERIES> a : this.timeSeriesHolder.entrySet()) { 140 INTERNALSERIES sub = a.getValue().get(start,end); 141 times = sub.getTimes(); 142 inputs.put(a.getKey(), sub.getData()); 143 } 144 try{ 145 t.set(times, inputs); 146 } 147 catch(Exception e){ 148 149 } 150 return t; 151 } 152 @Override 153 public TIMESERIES get(long time, int nbefore, int nafter, TIMESERIES output) { 154 HashMap<String, ALLINPUT> inputs = new HashMap<String,ALLINPUT>(); 155 long[] times = null; 156 for (Entry<String, INTERNALSERIES> a : this.timeSeriesHolder.entrySet()) { 157 INTERNALSERIES sub = a.getValue().get(time,nbefore,nafter,output.timeSeriesHolder.get(a.getKey())); 158 times = sub.getTimes(); 159 inputs.put(a.getKey(), sub.getData()); 160 } 161 try{ 162 output.set(times, inputs); 163 } 164 catch(Exception e){ 165 166 } 167 return output; 168 } 169 170 /** 171 * @return an instance of the internal series held 172 */ 173 public abstract INTERNALSERIES internalNewInstance(); 174 175 @Override 176 public TIMESERIES get(long time, long threshbefore, long threshafter) { 177 TIMESERIES t = newInstance(); 178 HashMap<String, ALLINPUT> inputs = new HashMap<String,ALLINPUT>(); 179 long[] times = null; 180 for (Entry<String, INTERNALSERIES> a : this.timeSeriesHolder.entrySet()) { 181 INTERNALSERIES sub = a.getValue().get(time,threshbefore,threshafter); 182 times = sub.getTimes(); 183 inputs.put(a.getKey(), sub.getData()); 184 } 185 try{ 186 t.set(times, inputs); 187 } 188 catch(Exception e){ 189 190 } 191 return t; 192 } 193 194 /** 195 * @param names 196 * @return a new time series containing sub time series by name 197 */ 198 public TIMESERIES collectionByNames(String... names) { 199 Map<String, ALLINPUT> ret = new HashMap<String, ALLINPUT>(); 200 ArrayList<long[]> times = new ArrayList<long[]>(); 201 for (String name: names) { 202 INTERNALSERIES exists = this.timeSeriesHolder.get(name); 203 if(exists != null) { 204 ret.put(name, exists.getData()); 205 times.add(exists.getTimes()); 206 } 207 } 208 209 TIMESERIES rets = newInstance(); 210 Iterator<long[]> titer = times.iterator(); 211 try { 212 rets.set(titer.next(), ret); 213 } catch (TimeSeriesSetException e) { 214 } 215 return rets; 216 } 217 218 /** 219 * @param names 220 * @return a new time series containing sub time series by name 221 */ 222 public TIMESERIES collectionByNames(Collection<String> names){ 223 return collectionByNames(names.toArray(new String[names.size()])); 224 } 225 226 /** 227 * @return the set of names of the time series in this collection 228 */ 229 public Set<String> getNames(){ 230 Set<String> copy = new HashSet<String>(); 231 for (String string : this.timeSeriesHolder.keySet()) { 232 copy.add(string); 233 } 234 return copy; 235 } 236 237 /** 238 * @return number of series held 239 */ 240 public int nSeries() { 241 return this.timeSeriesHolder.size(); 242 } 243 244 /** 245 * process the internal series held by this collection with this processor 246 * @param tsp 247 * @return a new instance of each internal series held in the same type of collection 248 */ 249 public TIMESERIES processInternal(TimeSeriesProcessor<ALLINPUT, SINGLEINPUT,INTERNALSERIES> tsp){ 250 TIMESERIES inst = newInstance(); 251 for (Entry<String, INTERNALSERIES> type: this.timeSeriesHolder.entrySet()) { 252 try { 253 inst.addTimeSeries(type.getKey(), type.getValue().process(tsp)); 254 } catch (IncompatibleTimeSeriesException e) { 255 } 256 } 257 return inst; 258 } 259 260 /** 261 * process the internal series held by this collection with this processor 262 * @param tsp 263 * @return each held instance processed 264 */ 265 public TIMESERIES processInternalInplace(TimeSeriesProcessor<ALLINPUT, SINGLEINPUT,INTERNALSERIES> tsp){ 266 TIMESERIES inst = newInstance(); 267 for (Entry<String, INTERNALSERIES> type: this.timeSeriesHolder.entrySet()) { 268 try { 269 inst.addTimeSeries(type.getKey(), type.getValue().processInplace(tsp)); 270 } catch (IncompatibleTimeSeriesException e) { 271 } 272 } 273 return inst; 274 } 275 276 /** 277 * @param <OUTPUTALL> 278 * @param <OUTPUTSINGLE> 279 * @param <OUTPUTTS> 280 * @param <OUTPUTTSC> 281 * @param tsc the method to convert each item 282 * @param inst the instance to be filled 283 * @return the inputed instance for convenience 284 */ 285 public < 286 OUTPUTALL, 287 OUTPUTSINGLE, 288 OUTPUTTS extends TimeSeries<OUTPUTALL, OUTPUTSINGLE, OUTPUTTS>, 289 OUTPUTTSC extends TimeSeriesCollection<OUTPUTALL, OUTPUTSINGLE, OUTPUTTSC, OUTPUTTS>> 290 OUTPUTTSC 291 convertInternal( 292 TimeSeriesConverter<ALLINPUT, SINGLEINPUT, INTERNALSERIES, OUTPUTALL, OUTPUTSINGLE, OUTPUTTS> tsc, 293 OUTPUTTSC inst 294 ) 295 { 296 for (Entry<String, INTERNALSERIES> type: this.timeSeriesHolder.entrySet()) { 297 try { 298 inst.addTimeSeries(type.getKey(), type.getValue().convert(tsc)); 299 } catch (IncompatibleTimeSeriesException e) { 300 } 301 } 302 return inst; 303 } 304 305 /** 306 * @param <OUTPUTALL> 307 * @param <OUTPUTSINGLE> 308 * @param <OUTPUTTS> 309 * @param <OUTPUTTSC> 310 * @param tsc the method to convert each item 311 * @param tsp a processor to apply during conversion 312 * @param inst the instance to be filled 313 * @return the inputed instance for convenience 314 */ 315 public < 316 OUTPUTALL, 317 OUTPUTSINGLE, 318 OUTPUTTS extends TimeSeries<OUTPUTALL, OUTPUTSINGLE, OUTPUTTS>, 319 OUTPUTTSC extends TimeSeriesCollection<OUTPUTALL, OUTPUTSINGLE, OUTPUTTSC, OUTPUTTS>> 320 OUTPUTTSC 321 convertInternal( 322 TimeSeriesConverter<ALLINPUT, SINGLEINPUT, INTERNALSERIES, OUTPUTALL, OUTPUTSINGLE, OUTPUTTS> tsc, 323 TimeSeriesProcessor<OUTPUTALL, OUTPUTSINGLE,OUTPUTTS> tsp, 324 OUTPUTTSC inst 325 ) 326 { 327 for (Entry<String, INTERNALSERIES> type: this.timeSeriesHolder.entrySet()) { 328 try { 329 inst.addTimeSeries(type.getKey(), type.getValue().convert(tsc,tsp)); 330 } catch (IncompatibleTimeSeriesException e) { 331 } 332 } 333 return inst; 334 } 335 336 337 @Override 338 public Iterator<IndependentPair<Long, Map<String, SINGLEINPUT>>> iterator() { 339 throw new UnsupportedOperationException(); 340 } 341 342 @Override 343 public long[] getTimes() { 344 throw new UnsupportedOperationException(); 345 } 346 347 @Override 348 public int size() { 349 throw new UnsupportedOperationException(); 350 } 351 352 @Override 353 public void set(long[] time, Map<String, ALLINPUT> data)throws TimeSeriesSetException { 354 for (Entry<String, ALLINPUT> l : data.entrySet()) { 355 INTERNALSERIES instance = internalNewInstance(); 356 instance.internalAssign(time,l.getValue()); 357 this.timeSeriesHolder.put(l.getKey(), instance); 358 } 359 360 } 361}