Jpp 20.0.0-rc.2
the software that should make you happy
Loading...
Searching...
No Matches
JCollection.hh
Go to the documentation of this file.
1#ifndef __JTOOLS__JCOLLECTION__
2#define __JTOOLS__JCOLLECTION__
3
4#include <vector>
5#include <cmath>
6#include <limits>
7#include <algorithm>
8
9#include "JLang/JClass.hh"
10#include "JLang/JException.hh"
11#include "JLang/JLangToolkit.hh"
12#include "JMath/JZero.hh"
13#include "JMath/JMath.hh"
14#include "JIO/JSerialisable.hh"
15#include "JTools/JDistance.hh"
19
20/**
21 * \file
22 *
23 * General purpose class for a collection of sorted elements.
24 * \author mdejong
25 */
26namespace JTOOLS {}
27namespace JPP { using namespace JTOOLS; }
28
29namespace JTOOLS {
30
31 using JMATH::JMath;
32 using JIO::JReader;
33 using JIO::JWriter;
35 using JLANG::JClass;
37
38
39 /**
40 * General purpose class for collection of elements, see:
41 \htmlonly
42 <a href="JTools.PDF";>Collection of elements.</a>
43 \endhtmlonly
44 *
45 * This class implements the JMappableCollection and JAbstractCollection interfaces.
46 *
47 * The data type of the elements of the collection should have the following policy
48 * type definition and member methods.
49 * <pre>
50 * typedef <abscissa type> abscissa_type;
51 * typedef <ordinate type> ordinate_type;
52 *
53 * (constructor)(abscissa_type, ordinate_type);
54 *
55 * abscissa_type %getX() const;
56 * ordinate_type %getY() const;
57 * ordinate_type& %getY();
58 * </pre>
59 *
60 * The elements in a collection are sorted according to their abscissa values and
61 * the given distance operator.
62 * The distance operator constitues a binary method returning the distance between
63 * two abscissa values; The default distance operator is JDistance.
64 *
65 * For the binary I/O of a collection of elements, the data structure of the elements
66 * should provide for an implementation of the following operators:
67 * <pre>
68 * JReader& operator>>(JReader& in);
69 * JWriter& operator<<(JWriter& out);
70 * </pre>
71 */
72 template<class JElement_t, class JDistance_t = JDistance<typename JElement_t::abscissa_type> >
73 class JCollection :
74 public std::vector<JElement_t>,
75 public JMappableCollection<typename JElement_t::abscissa_type,
76 typename JElement_t::ordinate_type>,
77 public JAbstractCollection<typename JElement_t::abscissa_type>,
78 public JMath< JCollection<JElement_t, JDistance_t> >
79 {
80 public:
81
82 typedef typename JElement_t::abscissa_type abscissa_type;
83 typedef typename JElement_t::ordinate_type ordinate_type;
84 typedef JElement_t value_type;
85 typedef JDistance_t distance_type;
86
88
90
91 typedef typename container_type::const_iterator const_iterator;
92 typedef typename container_type::const_reverse_iterator const_reverse_iterator;
93 typedef typename container_type::iterator iterator;
94 typedef typename container_type::reverse_iterator reverse_iterator;
95
98
100
101
102 /**
103 * Auxiliary class for ordering of objects in the collection by their abscissa values.
104 */
105 struct JComparator {
106 /**
107 * Comparison of elements.
108 *
109 * \param first first element
110 * \param second second element
111 * \return true if first element less than second element; else false
112 */
113 inline bool operator()(const JElement_t& first,
114 const JElement_t& second) const
115 {
116 return this->getDistance(first.getX(), second.getX()) > 0.0;
117 }
118
119
120 /**
121 * Comparison of element and abscissa value.
122 *
123 * \param element element
124 * \param x abscissa value
125 * \return true if element less than abscissa value; else false
126 */
127 inline bool operator()(const JElement_t& element, typename JClass<abscissa_type>::argument_type x) const
128 {
129 return this->getDistance(element.getX(), x) > 0.0;
130 }
131
132
133 /**
134 * Function object for distance evaluation.
135 */
136 JDistance_t getDistance;
137 };
138
139
140 /**
141 * Default constructor.
142 */
144 {}
145
146
147 /**
148 * Clear.
149 */
150 virtual void clear() override
151 {
152 container_type::clear();
153 }
154
155
156 /**
157 * Get ordinate value.
158 *
159 * \param x abscissa value
160 * \return ordinate value
161 */
162 virtual const ordinate_type& get(typename JClass<abscissa_type>::argument_type x) const override
163 {
164 const_iterator i = this->lower_bound(x);
165
166 if (i == this->end() || this->getDistance(x, i->getX()) > distance_type::precision) {
167 THROW(JValueOutOfRange, "Invalid abscissa value " << x);
168 }
169
170 return i->getY();
171 }
172
173
174 /**
175 * Get ordinate value.
176 *
177 * \param x abscissa value
178 * \return ordinate value
179 */
181 {
182 iterator i = this->lower_bound(x);
183
184 if (i == this->end() || this->getDistance(x, i->getX()) > distance_type::precision) {
185 i = container_type::insert(i, value_type(x, JMATH::getZero<ordinate_type>()));
186 }
187
188 return i->getY();
189 }
190
191
192 /**
193 * Get number of elements.
194 *
195 * \return number of elements
196 */
197 virtual int getSize() const override
198 {
199 return (int) this->size();
200 }
201
202
203 /**
204 * Get abscissa value.
205 *
206 * \param index index
207 * \return abscissa value
208 */
209 virtual abscissa_type getX(int index) const override
210 {
211 return this->at(index).getX();
212 }
213
214
215 /**
216 * Get minimal abscissa value.
217 *
218 * \return abscissa value
219 */
220 virtual abscissa_type getXmin() const override
221 {
222 return this->begin()->getX();
223 }
224
225
226 /**
227 * Get maximal abscissa value.
228 *
229 * \return abscissa value
230 */
231 virtual abscissa_type getXmax() const override
232 {
233 return this->rbegin()->getX();
234 }
235
236
237
238 /**
239 * Get ordinate value.
240 *
241 * \param index index
242 * \return ordinate value
243 */
244 const ordinate_type& getY(int index) const
245 {
246 return this->at(index).getY();
247 }
248
249
250 /**
251 * Get ordinate value.
252 *
253 * \param index index
254 * \return ordinate value
255 */
256 ordinate_type& getY(int index)
257 {
258 return this->at(index).getY();
259 }
260
261
262 /**
263 * Transform collection.
264 *
265 * \param transformer element transformer
266 */
267 void transform(const transformer_type& transformer)
268 {
269 for (iterator i = this->begin(); i != this->end(); ++i) {
270 *i = transformer(*i);
271 }
272
273 sort();
274 }
275
276
277 /**
278 * Sort elements.
279 */
280 void sort()
281 {
282 std::sort(this->begin(), this->end(), compare);
283 }
284
285
286 /**
287 * Get first position of element <tt>i</tt>, where <tt>x >= i->getX()</tt>.
288 *
289 * \param x abscissa value
290 * \return position of corresponding element
291 */
293 {
294 return std::lower_bound(this->begin(), this->end(), x, compare);
295 }
296
297
298 /**
299 * Get first position of element <tt>i</tt>, where <tt>x >= i->getX()</tt>.
300 *
301 * \param x abscissa value
302 * \return position of corresponding element
303 */
305 {
306 return std::lower_bound(this->begin(), this->end(), x, compare);
307 }
308
309
310 /**
311 * Insert element.
312 *
313 * \param element element
314 * \return (iterator, status), where status is true if inserted; else false
315 */
317 {
318 iterator i = this->lower_bound(element.getX());
319
320 if (i == this->end() || this->getDistance(element.getX(), i->getX()) > 0.0)
321 return pair_type(container_type::insert(i, element), true);
322 else
323 return pair_type(this->end(), false);
324 }
325
326
327 /**
328 * Configure collection.
329 *
330 * \param bounds abscissa values
331 */
336
337
338 /**
339 * Configure collection.
340 *
341 * \param bounds abscissa values
342 * \param value ordinate value
343 */
346 {
347 this->resize(bounds.getSize());
348
349 for (iterator i = this->begin(); i != this->end(); ++i) {
350
351 const abscissa_type x = bounds.getX(std::distance(this->begin(),i));
352
353 *i = value_type(x,value);
354 }
355 }
356
357
358 /**
359 * Configure collection.
360 *
361 * \param bounds abscissa values
362 * \param function function
363 */
364 template<class JFunction1D_t>
366 const JFunction1D_t& function)
367 {
368 using namespace JLANG;
369
370 collection_type* out = (is_identical(*this, function) ? new collection_type() : this);
371
372 for (int i = 0; i != bounds.getSize(); ++i) {
373
374 const abscissa_type x = bounds.getX(i);
375
376 out->put(x, function(x));
377 }
378
379 if (is_identical(*this, function)) {
380
381 this->swap(*out);
382
383 delete out;
384 }
385 }
386
387
388 /**
389 * Test whether collections are compatible.
390 *
391 * \param collection collection
392 * \return true if collections are compatible; else false
393 */
394 bool is_compatible(const JCollection& collection) const
395 {
396 if (this->empty() || collection.empty()) {
397
398 return true;
399
400 } else {
401
402 const double precision = JDistance<abscissa_type>::precision;
403
404 const_iterator p = this->begin();
405 const_iterator q = collection.begin();
406
407 if (getDistance(p->getX(), q->getX()) > precision) {
408
409 do {
410 ++p;
411 } while (p != this->end() && getDistance(p->getX(), q->getX()) > precision);
412
413 } else if (getDistance(q->getX(), p->getX()) > precision) {
414
415 do {
416 ++q;
417 } while (q != collection.end() && getDistance(q->getX(), p->getX()) > precision);
418 }
419
420 for ( ; p != this->end() && q != collection.end(); ++p, ++q) {
421 if (fabs(getDistance(p->getX(), q->getX())) > precision) {
422 return false;
423 }
424 }
425
426 return true;
427 }
428 }
429
430
431 /**
432 * Check if given abscissa is in range of this collection.
433 *
434 * \param x abscissa value
435 * \return true if in tange: else false
436 */
438 {
439 if (!this->empty())
440 return (this->getDistance(this->getXmin(), x) >= 0.0 &&
441 this->getDistance(this->getXmax(), x) <= 0.0);
442 else
443 return false;
444 }
445
446
447 /**
448 * Negate collection.
449 *
450 * \return this collection
451 */
453 {
454 for (iterator i = this->begin(); i != this->end(); ++i) {
455 i->getY() = -i->getY();
456 }
457
458 return *this;
459 }
460
461
462 /**
463 * Add collection.
464 *
465 * \param collection collection
466 * \return this collection
467 */
468 JCollection& add(const JCollection& collection)
469 {
470 if (!collection.empty()) {
471
472 if (this->empty()) {
473
474 for (const_iterator i = collection.begin(); i != collection.end(); ++i) {
475 this->put(i->getX(), +i->getY());
476 }
477
478 } else if (this->is_compatible(collection)) {
479
480 const double precision = JDistance<abscissa_type>::precision;
481
482 iterator p = this->begin();
483 const_iterator q = collection.begin();
484
485 if (getDistance(p->getX(), q->getX()) > precision) {
486
487 do {
488 ++p;
489 } while (p != this->end() && getDistance(p->getX(), q->getX()) > precision);
490
491 } else if (getDistance(q->getX(), p->getX()) > precision) {
492
493 do {
494 ++q;
495 } while (q != collection.end() && getDistance(q->getX(), p->getX()) > precision);
496 }
497
498 const_iterator i = q;
499
500 for ( ; p != this->end() && i != collection.end(); ++p, ++i) {
501 p->getY() += i->getY();
502 }
503
504 for ( ; i != collection.end(); ++i) {
505 this->put(i->getX(), +i->getY());
506 }
507
508 for (i = collection.begin(); i != q; ++i) {
509 this->put(i->getX(), +i->getY());
510 }
511
512 } else {
513
514 THROW(JException, "JCollection::add(): collections incompatible.");
515 }
516 }
517
518 return *this;
519 }
520
521
522 /**
523 * Subtract collection.
524 *
525 * \param collection collection
526 * \return this collection
527 */
528 JCollection& sub(const JCollection& collection)
529 {
530 if (!collection.empty()) {
531
532 if (this->empty()) {
533
534 for (const_iterator i = collection.begin(); i != collection.end(); ++i) {
535 this->put(i->getX(), -i->getY());
536 }
537
538 } else if (this->is_compatible(collection)) {
539
540 const double precision = JDistance<abscissa_type>::precision;
541
542 iterator p = this->begin();
543 const_iterator q = collection.begin();
544
545 if (getDistance(p->getX(), q->getX()) > precision) {
546
547 do {
548 ++p;
549 } while (p != this->end() && getDistance(p->getX(), q->getX()) > precision);
550
551 } else if (getDistance(q->getX(), p->getX()) > precision) {
552
553 do {
554 ++q;
555 } while (q != collection.end() && getDistance(q->getX(), p->getX()) > precision);
556 }
557
558 const_iterator i = q;
559
560 for ( ; p != this->end() && i != collection.end(); ++p, ++i) {
561 p->getY() -= i->getY();
562 }
563
564 for ( ; i != collection.end(); ++i) {
565 this->put(i->getX(), -i->getY());
566 }
567
568 for (i = collection.begin(); i != q; ++i) {
569 this->put(i->getX(), -i->getY());
570 }
571
572 } else {
573
574 THROW(JException, "JCollection::sub(): collections incompatible.");
575 }
576 }
577
578 return *this;
579 }
580
581
582 /**
583 * Scale contents.
584 *
585 * \param value multiplication factor
586 * \return this collection
587 */
588 JCollection& mul(const double value)
589 {
590 for (iterator i = this->begin(); i != this->end(); ++i) {
591 i->getY() *= value;
592 }
593
594 return *this;
595 }
596
597
598 /**
599 * Scale contents.
600 *
601 * \param value division factor
602 * \return this collection
603 */
604 JCollection& div(const double value)
605 {
606 for (iterator i = this->begin(); i != this->end(); ++i) {
607 i->getY() /= value;
608 }
609
610 return *this;
611 }
612
613
614 /**
615 * Add offset.
616 *
617 * \param value offset
618 * \return this collection
619 */
621 {
622 for (iterator i = this->begin(); i != this->end(); ++i) {
623 i->getY() += value;
624 }
625
626 return *this;
627 }
628
629
630 /**
631 * Subtract offset.
632 *
633 * \param value offset
634 * \return this collection
635 */
637 {
638 for (iterator i = this->begin(); i != this->end(); ++i) {
639 i->getY() -= value;
640 }
641
642 return *this;
643 }
644
645
646 /**
647 * Add function.
648 *
649 * \param function function
650 * \return this collection
651 */
652 template<class JFunction1D_t>
653 JCollection& add(const JFunction1D_t& function)
654 {
655 for (iterator i = this->begin(); i != this->end(); ++i) {
656 i->getY() += function(i->getX());
657 }
658
659 return *this;
660 }
661
662
663 /**
664 * Subtract function.
665 *
666 * \param function function
667 * \return this collection
668 */
669 template<class JFunction1D_t>
670 JCollection& sub(const JFunction1D_t& function)
671 {
672 for (iterator i = this->begin(); i != this->end(); ++i) {
673 i->getY() -= function(i->getX());
674 }
675
676 return *this;
677 }
678
679
680 /**
681 * Add offset to collaction.
682 *
683 * \param collection collection
684 * \param value offset
685 * \return collection
686 */
688 {
689 return collection.add(value);
690 }
691
692
693 /**
694 * Subtract offset from collaction.
695 *
696 * \param collection collection
697 * \param value offset
698 * \return collection
699 */
701 {
702 return collection.sub(value);
703 }
704
705
706 /**
707 * Add function.
708 *
709 * \param collection collection
710 * \param function function
711 * \return this collection
712 */
713 template<class JFunction1D_t>
714 friend JCollection& operator+=(JCollection& collection, const JFunction1D_t& function)
715 {
716 return collection.add(function);
717 }
718
719
720 /**
721 * Subtract function.
722 *
723 * \param collection collection
724 * \param function function
725 * \return this collection
726 */
727 template<class JFunction1D_t>
728 friend JCollection& operator-=(JCollection& collection, const JFunction1D_t& function)
729 {
730 return collection.sub(function);
731 }
732
733
734 /**
735 * Read collection from input.
736 *
737 * \param in reader
738 * \param collection collection
739 * \return reader
740 */
741 friend inline JReader& operator>>(JReader& in, JCollection& collection)
742 {
743 int n;
744
745 if (in >> n) {
746
747 collection.resize(n);
748
749 for (typename JCollection::iterator i = collection.begin(); i != collection.end(); ++i) {
750 in >> *i;
751 }
752 }
753
754 return in;
755 }
756
757
758 /**
759 * Write collection to output.
760 *
761 * \param out writer
762 * \param collection collection
763 * \return writer
764 */
765 friend inline JWriter& operator<<(JWriter& out, const JCollection& collection)
766 {
767 const int n = collection.size();
768
769 out << n;
770
771 for (typename JCollection::const_iterator i = collection.begin(); i != collection.end(); ++i) {
772 out << *i;
773 }
774
775 return out;
776 }
777
778
779 /**
780 * Get comparator.
781 *
782 * \return comparator
783 */
785 {
786 return compare;
787 }
788
789
790 /**
791 * Function object for distance evaluation.
792 */
793 JDistance_t getDistance;
794
795
796 protected:
797 /**
798 * Function object for comparison.
799 */
801
802
803 /**
804 * Resize collection
805 *
806 * \param size size
807 */
808 void resize(typename container_type::size_type size)
809 {
810 container_type::resize(size);
811 }
812
813 private:
814 void erase();
815 void push_back();
816 void pop_back();
817 };
818
819
820 /**
821 * Conversion of data points to integral values.
822 *
823 * The integration is based on the trapezoidal rule applied to the input data points.
824 *
825 * \param input collection
826 * \param output mappable collection
827 * \return integral
828 */
829 template<class JElement_t,
830 class JDistance_t>
831 inline typename JElement_t::ordinate_type
833 {
834 typedef typename JElement_t::ordinate_type ordinate_type;
835 typedef typename JCollection<JElement_t, JDistance_t>::const_iterator const_iterator;
836
837 ordinate_type V(JMATH::zero);
838
839 if (input.getSize() > 1) {
840
841 output.put(input.begin()->getX(), V);
842
843 for (const_iterator j = input.begin(), i = j++; j != input.end(); ++i, ++j) {
844
845 V += 0.5 * input.getDistance(i->getX(), j->getX()) * (i->getY() + j->getY());
846
847 output.put(j->getX(), V);
848 }
849 }
850
851 return V;
852 }
853}
854
855#endif
Exceptions.
#define THROW(JException_t, A)
Marco for throwing exception with std::ostream compatible message.
Base class for data structures with artithmetic capabilities.
Definition of zero value for any class.
Interface for binary input.
Interface for binary output.
General exception.
Definition JException.hh:24
Exception for accessing a value in a collection that is outside of its range.
General purpose class for collection of elements, see: <a href="JTools.PDF";>Collection of elements....
Definition JSet.hh:22
friend JCollection & operator-=(JCollection &collection, const JFunction1D_t &function)
Subtract function.
friend JCollection & operator+=(JCollection &collection, typename JClass< ordinate_type >::argument_type value)
Add offset to collaction.
std::pair< const_iterator, bool > pair_type
void configure(const JAbstractCollection< abscissa_type > &bounds)
Configure collection.
JCollection & add(const JFunction1D_t &function)
Add function.
void resize(typename container_type::size_type size)
Resize collection.
JCollection & sub(const JFunction1D_t &function)
Subtract function.
friend JReader & operator>>(JReader &in, JCollection &collection)
Read collection from input.
virtual abscissa_type getXmin() const override
Get minimal abscissa value.
JCollection< JElement_t, JDistance_t > collection_type
void sort()
Sort elements.
iterator lower_bound(typename JClass< abscissa_type >::argument_type x)
Get first position of element i, where x >= i->getX().
void configure(const JAbstractCollection< abscissa_type > &bounds, typename JClass< ordinate_type >::argument_type value)
Configure collection.
JDistance_t getDistance
Function object for distance evaluation.
virtual const ordinate_type & get(typename JClass< abscissa_type >::argument_type x) const override
Get ordinate value.
JElement_t value_type
JElement_t::ordinate_type ordinate_type
virtual abscissa_type getX(int index) const override
Get abscissa value.
JCollection & div(const double value)
Scale contents.
JCollection & negate()
Negate collection.
friend JWriter & operator<<(JWriter &out, const JCollection &collection)
Write collection to output.
ordinate_type & getY(int index)
Get ordinate value.
bool in_range(typename JClass< abscissa_type >::argument_type x) const
Check if given abscissa is in range of this collection.
void configure(const JAbstractCollection< abscissa_type > &bounds, const JFunction1D_t &function)
Configure collection.
container_type::reverse_iterator reverse_iterator
std::vector< value_type > container_type
virtual int getSize() const override
Get number of elements.
friend JCollection & operator+=(JCollection &collection, const JFunction1D_t &function)
Add function.
JElement_t::abscissa_type abscissa_type
pair_type insert(const value_type &element)
Insert element.
JCollection()
Default constructor.
container_type::iterator iterator
virtual ordinate_type & get(typename JClass< abscissa_type >::argument_type x) override
Get ordinate value.
JCollection & mul(const double value)
Scale contents.
friend JCollection & operator-=(JCollection &collection, typename JClass< ordinate_type >::argument_type value)
Subtract offset from collaction.
const ordinate_type & getY(int index) const
Get ordinate value.
JDistance_t distance_type
JCollection & sub(const JCollection &collection)
Subtract collection.
container_type::const_iterator const_iterator
virtual abscissa_type getXmax() const override
Get maximal abscissa value.
JComparator compare
Function object for comparison.
JCollection & add(typename JClass< ordinate_type >::argument_type value)
Add offset.
JCollectionElementTransformer< value_type > transformer_type
const_iterator lower_bound(typename JClass< abscissa_type >::argument_type x) const
Get first position of element i, where x >= i->getX().
void transform(const transformer_type &transformer)
Transform collection.
virtual void clear() override
Clear.
container_type::const_reverse_iterator const_reverse_iterator
JCollection & sub(typename JClass< ordinate_type >::argument_type value)
Subtract offset.
bool is_compatible(const JCollection &collection) const
Test whether collections are compatible.
const JComparator & getComparator() const
Get comparator.
JCollection & add(const JCollection &collection)
Add collection.
Auxiliary classes and methods for language specific functionality.
T getZero()
Get zero value for a given data type.
Definition JZero.hh:26
static const JZero zero
Function object to assign zero value.
Definition JZero.hh:105
This name space includes all other name spaces (except KM3NETDAQ, KM3NET and ANTARES).
Auxiliary classes and methods for multi-dimensional interpolations and histograms.
JElement_t::ordinate_type integrate(const JCollection< JElement_t, JDistance_t > &input, typename JMappable< JElement_t >::map_type &output)
Conversion of data points to integral values.
const int n
Definition JPolint.hh:791
int j
Definition JPolint.hh:801
Template for generic class types.
Definition JClass.hh:80
JArgument< T >::argument_type argument_type
Definition JClass.hh:82
Auxiliary base class for aritmetic operations of derived class types.
Definition JMath.hh:347
Abstract interface for abscissa values of a collection of elements.
virtual int getSize() const =0
Get number of elements.
virtual abscissa_type getX(int index) const =0
Get abscissa value.
Interface for transformation of collection of elements.
Auxiliary class for ordering of objects in the collection by their abscissa values.
bool operator()(const JElement_t &element, typename JClass< abscissa_type >::argument_type x) const
Comparison of element and abscissa value.
bool operator()(const JElement_t &first, const JElement_t &second) const
Comparison of elements.
JDistance_t getDistance
Function object for distance evaluation.
Template class for distance evaluation.
Definition JDistance.hh:24
Template interface definition for associative collection of elements.
void put(typename JClass< key_type > ::argument_type key, typename JClass< mapped_type >::argument_type value)
Put pair-wise element (key,value) into collection.