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;
031
032import org.openimaj.ml.timeseries.converter.TimeSeriesConverter;
033import org.openimaj.ml.timeseries.processor.TimeSeriesProcessor;
034import org.openimaj.ml.timeseries.processor.interpolation.TimeSeriesInterpolation;
035import org.openimaj.util.pair.IndependentPair;
036
037/**
038 * A time series defines data at discrete points in time. The time series has
039 * the ability to return data at a specific point in time, return neighbours
040 * within some window, closest neighbours or n neighbours before and after a
041 * time.
042 * <p>
043 * These values can be used by a {@link TimeSeriesInterpolation} to get specific
044 * moments in time
045 *
046 * @author Sina Samangooei (ss@ecs.soton.ac.uk)
047 *
048 * @param <DATA>
049 *            the type of the data at each point in time
050 * @param <SINGLE_TYPE>
051 *            the type of the an element at a single point in time
052 * @param <RETURNTYPE>
053 *            the time series returned by the get
054 *
055 */
056public abstract class TimeSeries<DATA, SINGLE_TYPE, RETURNTYPE extends TimeSeries<DATA, SINGLE_TYPE, RETURNTYPE>>
057implements
058                Iterable<IndependentPair<Long, SINGLE_TYPE>>
059{
060
061        /**
062         * Same as calling {@link #get(long, int, int)} with spans as 0
063         *
064         * @param time
065         * @return the requested data or null.
066         */
067        public RETURNTYPE get(long time) {
068                return get(time, 0, 0);
069        }
070
071        /**
072         * returns the DATA at a specific point in time and those before and after
073         * to the number requested. This method may not return data for the specific
074         * requested time if it does not exists. If the time series is completely
075         * empty this function may return at an empty array however if at least 1
076         * data point exists and either nbefore and nafter are bigger than 1 then at
077         * least 1 datapoint will be returned.
078         * <p>
079         * Data should be returned in order
080         *
081         * @param time
082         * @param nbefore
083         * @param nafter
084         * @return all data found with these parameters
085         */
086        public abstract RETURNTYPE get(long time, int nbefore, int nafter);
087
088        /**
089         * Same as {@link #get(long, int, int)} but instead of createing the output
090         * DATA instance, an existing data instance is handed which is filled. For
091         * convenience this output is also returned
092         * <p>
093         * Data should be returned in order
094         *
095         * @param time
096         * @param nbefore
097         * @param nafter
098         * @param output
099         * @return all data found with these parameters
100         */
101        public abstract RETURNTYPE get(long time, int nbefore, int nafter, RETURNTYPE output);
102
103        /**
104         * returns the RETURNTYPE at a specific point in time and those before and
105         * after within the specified thresholds. This method may not return data
106         * for the specific requested time if it does not exists. Similarly this
107         * method may return an empty array if no time data is available within the
108         * window specified.
109         * <p>
110         * Data should be returned in order
111         *
112         * @param time
113         * @param threshbefore
114         * @param threshafter
115         * @return all data found with these parameters
116         */
117        public abstract RETURNTYPE get(long time, long threshbefore, long threshafter);
118
119        /**
120         * returns the RETURNTYPE between the specified time periods. This method
121         * may not return data for the specific requested time if it does not
122         * exists. Similarly this method may return an empty array if no time data
123         * is available within the window specified.
124         * <p>
125         * Data should be returned in order
126         *
127         * @param start
128         * @param end
129         * @return all data found with these parameters
130         */
131        public abstract RETURNTYPE get(long start, long end);
132
133        /**
134         * Set the data associated with each time. This function explicitly assumes
135         * that time.length == data.length and there exists a single data instance
136         * per time instance
137         *
138         * @param time
139         *            instances of time
140         * @param data
141         *            instances of data
142         * @throws TimeSeriesSetException
143         */
144        public abstract void set(long[] time, DATA data) throws TimeSeriesSetException;
145
146        /**
147         * @return all times
148         */
149        public abstract long[] getTimes();
150
151        /**
152         * @return all data
153         */
154        public abstract DATA getData();
155
156        /**
157         * @return an empty new instance of this timeseries type
158         */
159        public abstract RETURNTYPE newInstance();
160
161        /**
162         * @return the number of valid time steps in this timeseries
163         */
164        public abstract int size();
165
166        /**
167         * @param interpolate
168         *            assign this timeseries to the internal one, efforts should be
169         *            made to copy the data, not simply assign it
170         */
171        public abstract void internalAssign(RETURNTYPE interpolate);
172
173        /**
174         * @param times
175         * @param data
176         */
177        public void internalAssign(long[] times, DATA data) {
178                try {
179                        this.set(times, data);
180                } catch (final TimeSeriesSetException e) {
181                }
182        }
183
184        /**
185         * @return clone this time series
186         */
187        @SuppressWarnings("unchecked")
188        public RETURNTYPE copy() {
189                final RETURNTYPE t = newInstance();
190                t.internalAssign((RETURNTYPE) this);
191                return t;
192        }
193
194        /**
195         * process using the provided processor, return
196         *
197         * @param tsp
198         * @return a new instance processed
199         */
200        public RETURNTYPE process(TimeSeriesProcessor<DATA, SINGLE_TYPE, RETURNTYPE> tsp) {
201                final RETURNTYPE copy = copy();
202                tsp.process(copy);
203                return copy;
204        }
205
206        @SuppressWarnings("unchecked")
207        private RETURNTYPE self() {
208                return (RETURNTYPE) this;
209        }
210
211        /**
212         * Process using the provided processor
213         *
214         * @param tsp
215         * @return this object processed inplace
216         */
217        public RETURNTYPE processInplace(TimeSeriesProcessor<DATA, SINGLE_TYPE, RETURNTYPE> tsp) {
218                tsp.process(self());
219                return self();
220        }
221
222        /**
223         * Convert a {@link TimeSeries}
224         *
225         * @param <OUTDATA>
226         * @param <OUTSING>
227         * @param <OUTRET>
228         * @param converter
229         *            the converter
230         * @return the converted timeseries
231         */
232        public <OUTDATA, OUTSING, OUTRET extends TimeSeries<OUTDATA, OUTSING, OUTRET>> OUTRET convert(
233                        TimeSeriesConverter<DATA, SINGLE_TYPE, RETURNTYPE, OUTDATA, OUTSING, OUTRET> converter)
234        {
235                return converter.convert(self());
236        }
237
238        /**
239         * Convert a {@link TimeSeries}
240         *
241         * @param <OUTDATA>
242         * @param <OUTSING>
243         * @param <OUTRET>
244         * @param converter
245         *            the converter
246         * @param tsp
247         *            the processor
248         * @return the converted timeseries
249         */
250        public <OUTDATA, OUTSING, OUTRET extends TimeSeries<OUTDATA, OUTSING, OUTRET>> OUTRET convert(
251                        TimeSeriesConverter<DATA, SINGLE_TYPE, RETURNTYPE, OUTDATA, OUTSING, OUTRET> converter,
252                        TimeSeriesProcessor<OUTDATA, OUTSING, OUTRET> tsp)
253        {
254                return converter.convert(self(), tsp);
255        }
256
257        @Override
258        public abstract String toString();
259}