ClockWork DB CoreAPI 1.0.48
Abstract Time Series and Storage/Management Library
Loading...
Searching...
No Matches
time_series.hpp
1#ifndef HAVE_TOM__TIMESERIES_HPP
2#define HAVE_TOM__TIMESERIES_HPP
3
4#include <tom-util/defines.hpp>
5#include <tom-util/calendar.hpp>
6#include <tom-util/scalar.hpp>
7
8#include <vector>
9#include <algorithm>
10#include <iostream>
11
12namespace tom {
13
14namespace collections {
15
16 using namespace tom::calendars;
17
18class time_series;
19class time_series_iterator;
20class standard_time_series_iterator;
21
22// garbage collected time_series class
23// that wraps up basic time_series functionality
24class TOM_UTIL_API time_series
25{
26public:
27 // empty ts w/ calendar
28 time_series( ) : m_start_date_int( 0 ), m_end_date_int(0) { };
29 virtual ~time_series() { }
30
31 virtual time_series_iterator &begin() const = 0;
32 virtual time_series_iterator &end() const = 0;
33
34 virtual const observation &get_observation( date_int_type d ) const = 0;
35 virtual const observation &get_observation( date d ) const = 0;
36
37 // provide specific handlers for dates since they will need to
38 // be properly converted if time-series hold date_interval_observation
39 // values...which most(ALL!) date series will!
40 virtual void set_observation( date_int_type d, const Date & ) = 0;
41 virtual void set_observation( date d, const Date & ) = 0;
42
43 virtual void set_observation( date_int_type d, const observation & val ) = 0;
44 virtual void set_observation( date d, const observation & val ) = 0;
45 virtual void set_observation( const Date &d, const observation &val )
46 {
47 if ( d.is_normal() )
48 set_observation( date( d.value() ), val );
49 }
50
51 // useful helpers for native formats
52
53 // native float setters
54 void set_observation( date_int_type d, float f )
55 { set_observation(d, Float(f) ); }
56 void set_observation( date d, float f )
57 { set_observation(d, Float(f) ); }
58 void set_observation( const Date &d, float f )
59 { set_observation(d, Float(f) ); }
60
61 // native double setters
62 void set_observation( date_int_type d, double f )
63 { set_observation(d, Double(f) ); }
64 void set_observation( date d, double f )
65 { set_observation(d, Double(f) ); }
66 void set_observation( const Date &d, double f )
67 { set_observation(d, Double(f) ); }
68
69 // native std::string setters
70 virtual
71 void set_observation( date_int_type d, const std::string &f )
72 { set_observation(d, String(f) ); }
73 virtual
74 void set_observation( date d, const std::string &f )
75 { set_observation(d, String(f) ); }
76 virtual
77 void set_observation( const Date &d, const std::string &f )
78 { set_observation(d, String(f) ); }
79
80 // native const char * setters
81 virtual
82 void set_observation( date_int_type d, const char *f )
83 { set_observation(d, String(f) ); }
84 virtual
85 void set_observation( date d, const char *f )
86 { set_observation(d, String(f) ); }
87 virtual
88 void set_observation( const Date &d, const char *f )
89 { set_observation(d, String(f) ); }
90
91 // native int setters
92 void set_observation( date_int_type d, int f )
93 { set_observation(d, Int(f) ); }
94 void set_observation( date d, int f )
95 { set_observation(d, Int(f) ); }
96 void set_observation( const Date &d, int f )
97 { set_observation(d, Int(f) ); }
98
99 // native bool setters
100 void set_observation( date_int_type d, bool f )
101 { set_observation(d, Bool(f) ); }
102 void set_observation( date d, bool f )
103 { set_observation(d, Bool(f) ); }
104 void set_observation( const Date &d, bool f )
105 { set_observation(d, Bool(f) ); }
106
107 // native category_type setters
108 void set_observation( date_int_type d,
110 { set_observation(d, Int(f) ); }
111 void set_observation( date d, tom::value_type f )
112 { set_observation(d, Int(f) ); }
113 void set_observation( const Date &d, tom::value_type f )
114 { set_observation(d, Int(f) ); }
115
116
117 virtual const observation & operator[ ]( date_int_type d ) const = 0;
118 virtual observation & operator[ ]( date_int_type d ) = 0;
119 virtual const observation & operator[ ] ( date d ) const = 0;
120 virtual observation & operator[ ] ( date d ) = 0;
121
122 virtual std::ostream &print( std::ostream & ) const = 0;
123 virtual tom::calendars::calendar & get_calendar( ) const = 0;
124
125 virtual inline date_int_type get_first_date_int() const { return m_start_date_int; }
126 virtual inline date_int_type get_last_date_int() const { return m_end_date_int; }
127 inline date get_first_date() const { return get_calendar()( get_first_date_int() ); }
128 inline date get_last_date() const { return get_calendar()( get_last_date_int()); }
129
130 // allow optional exposing of void * to data space
131 // this will likely not remain, so don't use this unless you are tom mccubbin!
132 // DEFAULT impl returns NULL ptr. classes wishing to hand out ptrs
133 // to memory may do so by overriding this method
134 virtual const void *data() const { return NULL; }
135
136protected:
137 // these can be safely called w/out regard
138 // for 'd' being the actual start or end
139 date_int_type set_last_date_int( const date_int_type d );
140 date_int_type set_first_date_int( const date_int_type d );
141
142 date_int_type m_start_date_int; // first date inclusive
143 date_int_type m_end_date_int; // last date inclusive (not end())
144
145private:
146};
147
148// ostream << function
149inline
150std::ostream &
151operator<<( std::ostream &os, const time_series &ts )
152{
153 return ts.print(os);
154}
155
156class TOM_UTIL_API time_series_iterator
157{
158public:
159 virtual
161
162 virtual
164 operator++() = 0;
165
166 virtual
168 operator++(int) = 0;
169
170 virtual
172 operator--() = 0;
173
174 virtual
176 operator--(int) = 0;
177
178 virtual
179 bool
180 operator==( const tom::collections::time_series_iterator& rhs) const = 0;
181
182 virtual
183 bool
184 operator!=( const tom::collections::time_series_iterator& rhs) const = 0;
185
186 virtual
187 const observation &
188 operator*() const = 0;
189
190 virtual
191 const observation &
192 operator->() const = 0;
193
194 virtual
195 date
196 get_date() const = 0;
197
198 virtual
199 date_int_type
200 get_date_int() const = 0;
201
202 // dummy implementation
203 virtual
204 timespec
205 get_timespec() const { struct timespec spec {0,0}; return spec; }
206
207 virtual
208 calendar &
209 get_calendar() const = 0;
210
211};
213{
214public:
215 standard_time_series_iterator ( time_series &ts, date_int_type d ) :
216 m_ts( ts ), m_cal( ts.get_calendar() ), m_date_int(d)
217 { }
218
220 m_ts( ts ), m_cal( ts.get_calendar() ), m_date_int( m_cal(d) )
221 { }
222
223 virtual
225
226 virtual
228 operator++() { m_date_int++; return *this; }
229
230 virtual
232 operator++(int) { m_date_int++; return *this; }
233
234 virtual
236 operator--() { m_date_int--; return *this; }
237
238 virtual
240 operator--(int) { m_date_int--; return *this; }
241
242 virtual
243 bool
244 operator==( const tom::collections::time_series_iterator& rhs) const
245 {
246 return rhs.get_calendar() == m_cal &&
247 rhs.get_date_int() == m_date_int;
248 }
249
250 virtual
251 bool
252 operator!=( const tom::collections::time_series_iterator& rhs) const
253 {
254 return ! ( *this == rhs );
255 }
256
257 virtual
258 const observation &
259 operator*() const
260 {
261 return m_ts.get_observation( m_date_int );
262 }
263
264 virtual
265 const observation &
266 operator->() const
267 {
268 return m_ts.get_observation( m_date_int );
269 }
270
271 virtual
272 date
273 get_date() const { return m_cal( m_date_int ); }
274
275 virtual
276 date_int_type
277 get_date_int() const { return m_date_int; }
278
279 virtual
280 timespec
281 get_timespec() const
282 {
283 date d = get_date();
284 struct tm tm;
285 tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
286 tm.tm_year = d.year() - 1900;
287 tm.tm_mon = d.month();
288 tm.tm_mday = d.day();
289 struct timespec spec {0,0};
290 spec.tv_sec = mktime( &tm );
291 spec.tv_nsec = 0;
292 return spec;
293 }
294
295 virtual
296 calendar &
297 get_calendar() const { return m_cal; }
298
299protected:
300 time_series & m_ts;
301 calendar & m_cal;
302 date_int_type m_date_int;
303
304};
305
306template <typename T>
307class TOM_UTIL_API time_series_impl :
308 public time_series, public std::vector<typename T::value_type>
309{
310public:
311 typedef T value_type;
312 typedef typename std::vector<typename T::value_type > vector_type;
314 typedef typename vector_type::pointer pointer;
315 typedef typename vector_type::reference reference;
316 typedef typename vector_type::difference_type difference_type;
317 typedef std::random_access_iterator_tag iterator_category;
318
319 typedef typename vector_type::iterator iterator;
320 typedef typename vector_type::const_iterator const_iterator;
321
322 time_series_impl( calendar &cal ) :
323 vector_type(), m_align( OFFSET ), m_calendar( cal ),
324 m_first_date( 0 ), m_last_date( 0 ), m_min_first_date(0)
325 {
326 m_calendar_offset = cal( cal.get_first_date() );
327 }
328
329 template <typename Iter>
330 time_series_impl( calendar &cal, date_int_type start, Iter begin, Iter end ) :
331 vector_type( begin, end ), m_align( OFFSET ), m_calendar(cal),
332 m_first_date( start ), m_last_date( start + ( end - begin ) - 1 ),
333 m_min_first_date(start)
334 {
335 m_calendar_offset = cal( cal.get_first_date() );
336 }
337 template <typename IteratorT>
338 time_series_impl( calendar &cal, date start, IteratorT begin, IteratorT end ) :
339 vector_type( begin, end ), m_align( OFFSET ), m_calendar(cal),
340 m_first_date( cal( start ) ), m_last_date( cal( start ) + ( end - begin ) - 1 ),
341 m_min_first_date( m_first_date )
342 {
343 m_calendar_offset = cal( cal.get_first_date() );
344 }
345 virtual ~time_series_impl() { }
346
347 virtual time_series_iterator& begin() const
348 {
349 return * new standard_time_series_iterator( const_cast<time_series_impl &>(*this), get_first_date_int() );
350 }
351 virtual time_series_iterator &end() const
352 {
353 return *new standard_time_series_iterator( const_cast<time_series_impl &>(*this), get_last_date_int() + 1 );
354 }
355
356 virtual
357 const observation &
358 get_observation( date_int_type d ) const
359 {
360 if ( in_range(d) )
361 return m_return_value = *( real_begin() + index_of(d) );
362 else
363 // no need to refer to T, as ND is ND, right?
364 // and because i don't yet have a fix for the
365 // String static init problem / SEGV!!
366 return Int::HAS_NO_DATA; // ND in real life
367 }
368 virtual const observation &get_observation( const date d ) const ;
369
370 // hidden (by name only) method that does the work
371 // all methods should redirect to this one !!!
372 void
373 set_observation_( date_int_type d, const T &v )
374 {
375 // convert to native type first!
376 //value_type v( val );
377
378 // first handle ND values which may shrink the series,
379 // or make it empty
380 if ( v.flag() == tom::value_type::no_data() )
381 {
382 // setting empty series point to ND - no effect
383 if ( is_empty() )
384 return;
385
386 // set series w/ single point to ND - become empty ts
387 else if ( get_first_date_int() == get_last_date_int() && d == get_first_date_int() )
388 {
389 set_first_date(0);
390 set_last_date(0);
391 return;
392 }
393
394 // ND outside or at edge of range
395 else if ( ! ( d > get_first_date_int() && d < get_last_date_int() ) )
396 {
397 // ND at last point, shrink range
398 if ( d == get_last_date_int() )
399 unwind_end( d );
400
401 // ND at first point, shrink range
402 else if ( d == get_first_date_int() )
403 unwind_start( d );
404
405 // d outside range, no effect
406 return;
407 }
408 }
409 // empty series? set dates and allocate
410 if ( is_empty() )
411 {
412 set_first_date(d);
413 set_last_date(d);
414 extend(d);
415 }
416 // add past end? extend, init(ND), and adjust last_date
417 else if ( d > get_last_date_int() )
418 {
419 extend( d );
420 assign_nd( get_last_date_int() +1, d );
421 set_last_date(d);
422 }
423 // add before start?
424 else if ( d < get_first_date_int() )
425 {
426 // if aligned w/ offset
427 if ( get_alignment() == OFFSET )
428 {
429 // mark ourselved naturally aligned
430 set_alignment( NATURAL );
431 // extend for new expanded range
432 extend( get_last_date_int() );
433 // move data to proper offset
434 realign();
435 }
436 // init(ND)'s and set first_date
437 assign_nd( d, get_first_date_int() -1 );
438 set_first_date(d);
439 }
440 // for all, assign value...finally!
441 *(real_begin() + index_of( d )) = v.value();
442 }
443 virtual
444 void
445 set_observation( date_int_type d, const observation &val )
446 {
447 set_observation_( d, T(val) );
448 }
449 // date handlers - this should apply to Date, date_interval_observation,
450 // and date_interval_scalar<> classes
451 virtual void set_observation( date_int_type d, const Date &v )
452 {
453 set_observation_( d, T(v) );
454 }
455 virtual void set_observation( date d, const Date &v )
456 {
457 set_observation_( get_calendar()(d), T(v) );
458 }
459
460 virtual void set_observation( const date d, const observation & val );
461 void set_observation( const date_int_type d, const typename T::value_type & val );
462 void set_observation( const date d, const typename T::value_type & val );
463 void set_observation( const date_int_type d, tom::value_type val );
464 void set_observation( const date d, tom::value_type val );
465
466 virtual const observation & operator[ ]( const date_int_type d ) const ;
467 virtual observation & operator[ ]( const date_int_type d );
468 virtual const observation & operator[ ] ( const date d ) const ;
469 virtual observation & operator[ ] ( const date d ) ;
470
471 virtual std::ostream &print( std::ostream & ) const;
472
473 virtual
475 get_calendar() const { return m_calendar; }
476
477 date_int_type
478 get_first_date_int() const { return m_first_date; }
479
480 date_int_type
481 get_last_date_int() const { return m_last_date; }
482
483
484 bool
485 is_empty() const
486 {
487 if ( get_last_date_int() == 0 )
488 return true;
489 return false;
490 }
491 bool
492 in_range( date_int_type d ) const
493 {
494 if ( get_first_date_int() == 0 )
495 return false;
496 if ( d >= get_first_date_int() && d <= get_last_date_int() )
497 return true;
498 return false;
499 }
500 virtual const void *data() const
501 {
502 // ugly hack for now :(
503 return reinterpret_cast<const void *>( (&this->vector_type::front()) + index_of( get_first_date_int() ) );
504 }
505
506protected:
507 enum Alignment { OFFSET, NATURAL };
508
509 Alignment m_align;
510 calendar & m_calendar;
511 date_int_type m_calendar_offset;
512 date_int_type m_first_date;
513 date_int_type m_last_date;
514 date_int_type m_min_first_date;
515 // This acts as a observation to be returned where one is needed
516 mutable value_type m_return_value;
517 iterator real_begin() { return this->vector_type::begin(); }
518 iterator real_end() { return this->vector_type::end(); }
519 const_iterator real_begin() const { return this->vector_type::begin(); }
520 const_iterator real_end() const { return this->vector_type::end(); }
521
522 void
523 set_first_date( date_int_type d )
524 {
525 m_min_first_date = (d < m_min_first_date || m_min_first_date == 0 ) ?
526 d : m_min_first_date;
527 m_first_date = d;
528 }
529
530 void
531 set_last_date( date_int_type d ) { m_last_date = d; }
532
533 Alignment
534 get_alignment() const { return m_align; }
535 void
536 set_alignment( Alignment a ) { m_align = a; }
537
538 // how much shift is evident in vector alignment
539 // 1 is natural, otherwise it is offset by start date
540 int
541 get_offset() const
542 {
543 if ( get_alignment() == OFFSET )
544 //return get_first_date_int();
545 return m_min_first_date;
546 else
547 return m_calendar_offset;
548 }
549 // real index for date d in vector
550 size_t
551 index_of( date_int_type d ) const
552 {
553 return d - get_offset();
554 }
555 // extends vector to date d, filling w/ ND's
556 void
557 extend( date_int_type d )
558 {
559 if ( index_of(d) + 1 > this->size() )
560 this->resize( index_of( d ) + 1 );
561 }
562 // sets vector to ND in range of start - end, including end
563 void
564 assign_nd( date_int_type start, date_int_type end )
565 {
566 iterator b = real_begin() + index_of( start );
567 iterator e = real_begin() + index_of( end ) + 1;
568 // not reliable as T::no_data::value may not be initialized yet
569 // and will default to 0 if not!
570 // but lets give it a try as this runtime
571 std::fill( b, e, T::no_data::value );
572 // instead get the value based on function call guaranteed to work
573 //typename T::value_type tmp = tom::value_types::resolve_nd<typename T::value_type>::get_value_of_nd();
574 //std::fill( b, e, tmp );
575 }
576 void
577 unwind_end( date_int_type d )
578 {
579 while ( (--d) >= get_first_date_int() )
580 {
581 scalar_type tmp( *(real_begin() + index_of(d) ) );
582 if ( tmp.category() != tom::value_types::TOM_VALUE_NO_DATA )
583 {
584 set_last_date( d );
585 return;
586 }
587 }
588 set_last_date( get_first_date_int() );
589 }
590 void
591 unwind_start( date_int_type d )
592 {
593 // change the use of index_of so it and only it uses min-first-date
594 // then this should work!
595 while ( (++d) <= get_last_date_int() )
596 {
597 if ( scalar_type( *(real_begin() + index_of(d) ) ).category() != tom::value_types::TOM_VALUE_NO_DATA )
598 {
599 set_first_date( d );
600 return;
601 }
602 }
603 set_first_date( get_last_date_int() );
604 }
605 // after extending, move data forward in the vector
606 // by the difference of first_date and cal_offset
607 void
608 realign( )
609 {
610 size_t diff = get_last_date_int() - get_first_date_int() + 1;
611 std::copy_backward( real_begin(), real_begin() + diff,
612 real_begin() + this->vector_type::size() );
613 }
614
615};
616
617template <typename T>
618inline
619const observation &
621{
622 date_int_type di = get_calendar()(d);
623 return this->get_observation( di );
624}
625template <typename T>
626inline
627void
628time_series_impl<T>::set_observation( const date d, const observation & val )
629{
630 date_int_type di = get_calendar()(d);
631 this->set_observation_( di, T(val) );
632}
633template <typename T>
634inline
635void
636time_series_impl<T>::set_observation( const date_int_type d, const typename T::value_type & val )
637{
638 set_observation_( d, T(val) );
639};
640template <typename T>
641inline
642void
643time_series_impl<T>::set_observation( const date d, const typename T::value_type & val )
644{
645 set_observation_( get_calendar()(d), T(val) );
646}
647template <typename T>
648inline
649void
650time_series_impl<T>::set_observation( const date_int_type d, tom::value_type val )
651{
652 set_observation_( d, T(val) );
653}
654template <typename T>
655inline
656void
657time_series_impl<T>::set_observation( const date d, tom::value_type val )
658{
659 set_observation_( get_calendar()(d), T(val) );
660}
661
662template <typename T>
663const observation &
664time_series_impl<T>::operator[ ]( const date_int_type d ) const
665{
666 if ( in_range(d) )
667 return m_return_value = *( real_begin() + index_of(d) );
668 else
669 return Int::HAS_NO_DATA; // ND in real life
670}
671template <typename T>
673time_series_impl<T>::operator[ ]( const date_int_type d )
674{
675 if ( in_range(d) )
676 return m_return_value = *( real_begin() + index_of(d) );
677 else
678 return m_return_value = tom::value_type::no_data(); // ND in real life
679}
680template <typename T>
681const observation &
682time_series_impl<T>::operator[ ] ( const date d ) const
683{
684 date_int_type di = get_calendar()(d);
685 return (*this)[di];
686}
687template <typename T>
689time_series_impl<T>::operator[ ] ( const date d )
690{
691 date_int_type di = get_calendar()(d);
692 return (*this)[di];
693}
694template <typename T>
695inline
696std::ostream &
697time_series_impl<T>::print( std::ostream & os) const
698{
699 calendar &cal = get_calendar();
700 if ( cal != ordinal_calendar::Instance() )
701 //for( time_series_iterator &it = begin(); it != end(); ++it )
702 //os << it.get_date() << ": " << *it << std::endl;
703 for( date_int_type di = get_first_date_int(); di <= get_last_date_int(); ++di )
704 os << cal(di) << ": " << get_observation(di) << std::endl;
705 else
706 //for( time_series_iterator &it = begin(); it != end(); ++it )
707 // os << it.get_date_int() << ": " << *it << std::endl;
708 for( date_int_type di = get_first_date_int(); di <= get_last_date_int(); ++di )
709 os << di << ": " << get_observation(di) << std::endl;
710
711 return os;
712}
713
714
715
716// Factory template to save some typeing for the
717// code-monkeys using the util libs...
718// It is safe to just use 'new time_series_impl<...>(...)'
719// yourself, this is just easier i think :)
720// eg. :
721//
722// time_series &ts =
723// float_time_series_factory::create<monthly_calendar>();
724//
725// creates a float time series with a monthly calendar
726// This is the same as just doing...
727//
728// time_series &ts =
729// *new time_series_impl<tom::Float,monthly_calendar>();
730//
731// NOTE: this may look like a memory leak in the waiting,
732// but the class is garbage collected, so pass it around
733// and forget about memory management. When it is no longer
734// referenced, it will be freed.
735
736template <typename T>
737struct TOM_UTIL_API time_series_impl_factory
738{
739 template <typename CalendarT>
740 static
742 create()
743 {
744 return *new time_series_impl<T>( CalendarT::Instance() );
745 }
746 template <typename CalendarT, typename IteratorT>
747 static
749 create(date start, IteratorT begin, IteratorT end)
750 {
751 return *new time_series_impl<T>( CalendarT::Instance(), start, begin, end);
752 }
753 template <typename CalendarT, typename IteratorT>
754 static
756 create(date_int_type start, IteratorT begin, IteratorT end)
757 {
758 return *new time_series_impl<T>( CalendarT::Instance(), start, begin, end);
759 }
760};
761
799
800// alias for commonly used timeseries
805
806} // end collections namespace
807} // end tom namespace
808
809#endif
Definition dates.hpp:22
Definition string.hpp:15
Definition calendar.hpp:120
Definition calendar.hpp:47
Definition time_series.hpp:309
Definition time_series.hpp:157
Definition time_series.hpp:25
Definition observation.hpp:13
Definition scalar.hpp:19
Definition value_types.hpp:381
Definition value_types.hpp:144
Definition time_series.hpp:738