1
// ---------------------------------------------------------------------------
3
// - afnix:mth module - real array samples class implementation -
4
// ---------------------------------------------------------------------------
5
// - This program is free software; you can redistribute it and/or modify -
6
// - it provided that this copyright notice is kept intact. -
8
// - This program is distributed in the hope that it will be useful, but -
9
// - without any warranty; without even the implied warranty of -
10
// - merchantability or fitness for a particular purpose. In no event shall -
11
// - the copyright holder be liable for any direct, indirect, incidental or -
12
// - special damages arising in any way out of the use of this software. -
13
// ---------------------------------------------------------------------------
14
// - copyright (c) 1999-2015 amaury darsch -
15
// ---------------------------------------------------------------------------
20
#include "Rsamples.hpp"
21
#include "QuarkZone.hpp"
22
#include "Exception.hpp"
26
// -------------------------------------------------------------------------
27
// - private section -
28
// -------------------------------------------------------------------------
30
// the default columns size
31
static const long RS_COLS_DEF = 1;
32
// the default row size
33
static const long RS_SIZE_DEF = 1024;
34
// the default number precision
35
static const long RS_PSIZ_DEF = 0;
36
// the default scientific flag
37
static const long RS_SFLG_DEF = false;
39
// this procedure returns a new rsamples for deserialization
40
static Serial* mksob (void) {
43
// register this array serial id
44
static const t_byte SERIAL_ID = Serial::setsid (SERIAL_RSPL_ID, mksob);
46
// -------------------------------------------------------------------------
48
// -------------------------------------------------------------------------
50
// create a default array
52
Rsamples::Rsamples (void) {
62
// create an array by columns
64
Rsamples::Rsamples (const long cols) {
66
throw Exception ("rsample-error", "invalid column size");
77
// create an array by name, info and columns
79
Rsamples::Rsamples (const String& name, const String& info, const long cols) {
81
throw Exception ("rsample-error", "invalid column size");
94
// copy construct this array
96
Rsamples::Rsamples (const Rsamples& that) {
99
// copy the size and allocate
100
d_name = that.d_name;
101
d_info = that.d_info;
102
d_cols = that.d_cols;
103
d_size = that.d_size;
104
d_rows = that.d_rows;
105
d_psiz = that.d_psiz;
106
d_sflg = that.d_sflg;
107
p_time = (that.p_time == nilp) ? nilp : new t_real[d_size];
108
p_data = (d_size == 0) ? nilp : new t_real*[d_size];
110
for (long i = 0; i < d_size; i++) {
111
// copy the time stamp
112
if (p_time != nilp) p_time[i] = that.p_time[i];
114
if (that.p_data[i] != nilp) {
115
p_data[i] = new t_real[d_cols];
116
for (t_long j = 0; j < d_cols; j++) p_data[i][j] = that.p_data[i][j];
117
} else p_data[i] = nilp;
126
// destroy this array samples
128
Rsamples::~Rsamples (void) {
129
for (t_long i = 0; i < d_size; i++) delete [] p_data[i];
134
// return the class name
136
String Rsamples::repr (void) const {
140
// return a clone of this object
142
Object* Rsamples::clone (void) const {
143
return new Rsamples (*this);
146
// return the array serial code
148
t_byte Rsamples::serialid (void) const {
149
return SERIAL_RSPL_ID;
152
// serialize this object
154
void Rsamples::wrstream (OutputStream& os) const {
157
// write the object name and info
158
d_name.wrstream (os);
159
d_info.wrstream (os);
160
// write the object data
161
Serial::wrlong (d_cols, os);
162
Serial::wrlong (d_size, os);
163
Serial::wrlong (d_rows, os);
164
Serial::wrlong (d_psiz, os);
165
Serial::wrbool (d_sflg, os);
166
// eventually write the time stamps
167
if (p_time != nilp) {
168
Serial::wrbool (true, os);
169
Serial::Block blok (RS_SIZE_DEF, Serial::Block::REAL);
170
for (long row = 0; row < d_rows; row++) {
171
blok.add (p_time[row]);
172
if (blok.full () == false) continue;
173
Serial::wrblok (blok, os);
176
if (blok.empty () == false) Serial::wrblok (blok, os);
178
Serial::wrbool (false, os);
181
if (p_data != nilp) {
182
Serial::wrbool (true, os);
183
long dlen = d_rows * d_cols;
184
Serial::Block blok (RS_SIZE_DEF, Serial::Block::REAL);
185
for (long k = 0; k < dlen; k++) {
186
long row = k / d_cols;
187
long col = k % d_cols;
188
blok.add (p_data[row][col]);
189
if (blok.full () == false) continue;
190
Serial::wrblok (blok, os);
193
if (blok.empty () == false) Serial::wrblok (blok, os);
195
Serial::wrbool (false, os);
204
// deserialize this object
206
void Rsamples::rdstream (InputStream& is) {
209
// get the object info
210
d_name.rdstream (is);
211
d_info.rdstream (is);
212
// get the object data
213
d_cols = Serial::rdlong (is);
214
d_size = Serial::rdlong (is);
215
d_rows = Serial::rdlong (is);
216
d_psiz = Serial::rdlong (is);
217
d_sflg = Serial::rdbool (is);
218
// check for time stamps
219
if (Serial::rdbool (is) == true) {
220
p_time = new t_real[d_size];
221
for (long i = 0; i < d_rows; i++) {
222
Block blok = Serial::rdblok (is);
223
long blen = blok.length ();
224
for (long k = 0; k < blen; k++) p_time[i+k] = blok.getreal (k);
227
for (long i = d_rows; i < d_size; i++) p_time[i] = Math::M_NAN;
230
if (Serial::rdbool (is) == true) {
231
p_data = new t_real*[d_size];
232
for (long i = 0; i < d_rows; i++) p_data[i] = new t_real[d_cols];
233
long dlen = d_rows * d_cols;
234
for (long i = 0; i < dlen; i++) {
235
Block blok = Serial::rdblok (is);
236
long blen = blok.length ();
237
for (long k = 0; k < blen; k++) {
238
long row = (i + k) / d_cols;
239
long col = (i + k) % d_cols;
244
p_data[row][col] = blok.getreal (k);
248
for (long i = d_rows; i < d_size; i++) p_data[i] = nilp;
257
// assign an array samples to this one
259
Rsamples& Rsamples::operator = (const Rsamples& that) {
260
// check for self-assignation
261
if (this == &that) return *this;
266
// delete the old array
267
for (long i = 0; i < d_size; i++) delete [] p_data[i];
268
delete [] p_data; p_data = nilp;
269
// copy the size and allocate
270
d_name = that.d_name;
271
d_info = that.d_info;
272
d_cols = that.d_cols;
273
d_size = that.d_size;
274
d_rows = that.d_rows;
275
d_psiz = that.d_psiz;
276
d_sflg = that.d_sflg;
277
p_time = (that.p_time == nilp) ? nilp : new t_real[d_size];
278
p_data = (d_size == 0) ? nilp : new t_real*[d_size];
280
for (long i = 0; i < d_size; i++) {
281
// copy the time stamp
282
if (p_time != nilp) p_time[i] = that.p_time[i];
284
if (that.p_data[i] != nilp) {
285
p_data[i] = new t_real[d_cols];
286
for (t_long j = 0; j < d_cols; j++) p_data[i][j] = that.p_data[i][j];
287
} else p_data[i] = nilp;
299
// get the samples name
301
String Rsamples::getname (void) const {
304
String result = d_name;
313
// set the samples name
315
void Rsamples::setname (const String& name) {
326
// set the samples info
328
void Rsamples::setinfo (const String& info) {
339
// get the samples info
341
String Rsamples::getinfo (void) const {
344
String result = d_info;
353
// clear this array samples
355
void Rsamples::clear (void) {
358
for (t_long i = 0; i < d_size; i++) delete [] p_data[i];
359
delete [] p_time; p_time = nilp;
360
delete [] p_data; p_data = nilp;
370
// get the number of rows
372
long Rsamples::getrows (void) const {
375
long result = d_rows;
384
// set the number of colimns
386
void Rsamples::setcols (const long cols) {
389
// check for valid columns
391
throw Exception ("rsample-error", "invalid column size");
404
// get the number of columns
406
long Rsamples::getcols (void) const {
409
long result = d_cols;
418
// set the number precision
420
void Rsamples::setpsiz (const long psiz) {
424
throw Exception ("rsamples-error", "invalid negative number precision");
434
// get the number precision
436
long Rsamples::getpsiz (void) const {
439
long result = d_psiz;
448
// set the scientific flag
450
void Rsamples::setsflg (const bool sflg) {
461
// get the scientific flag
463
bool Rsamples::getsflg (void) const {
466
bool result = d_sflg;
475
// return true if the samples are stamped
477
bool Rsamples::stamped (void) const {
480
bool result = (p_time != nilp);
489
// get a time value by position
491
t_real Rsamples::gettime (const long row) const {
494
// check for valid position
495
if ((row < 0) || (row >= d_rows)) {
496
throw Exception ("sample-error", "invalid row position");
498
t_real result = (p_time == nilp) ? Math::M_NAN : p_time[row];
507
// set a sample by position and value
509
void Rsamples::set (const long row, const long col, const t_real val) {
512
// check for valid position
513
if ((row < 0) || (row >= d_rows)) {
514
throw Exception ("sample-error", "invalid row position");
516
if ((col < 0) || (col >= d_cols)) {
517
throw Exception ("sample-error", "invalid column position");
520
p_data[row][col] = val;
528
// get a sample by position
530
t_real Rsamples::get (const long row, const long col) const {
533
// check for valid position
534
if ((row < 0) || (row >= d_rows)) {
535
throw Exception ("sample-error", "invalid row position");
537
if ((col < 0) || (col >= d_cols)) {
538
throw Exception ("sample-error", "invalid column position");
541
t_real result = p_data[row][col];
550
// add a new unitialized row
552
long Rsamples::newrow (void) {
555
// eventually resize the array
556
if ((d_rows + 1) > d_size) resize ((d_size == 0) ? 1 : (d_size * 2));
557
// save result and allocate
558
long result = d_rows;
559
p_data[d_rows++] = new t_real[d_cols];
560
// initialized as nan
561
for (long i = 0; i < d_cols; i++) p_data[result][i] = Math::M_NAN;
571
// add a new uninitialized row with a time stamp
573
long Rsamples::newrow (const t_real tval) {
576
// allocate the new row
577
long result = newrow ();
578
// check for non-allocated time
579
if ((p_time == nilp) && (tval == Math::M_NAN)) {
583
// eventually allocate the time stamps
584
if (p_time == nilp) {
585
p_time = new t_real[d_size];
586
for (long i = 0; i < d_size; i++) p_time[i] = Math::M_NAN;
588
// set the time stamp
589
p_time[result] = tval;
599
// resize this array samples
601
void Rsamples::resize (const long size) {
604
// check for resizing
605
if (size <= d_size) {
609
// allocate a new time stamp
610
t_real* tptr = (p_time == nilp) ? nilp : new t_real[size];
611
// allocate new array
612
t_real** data = new t_real*[size];
614
for (long i = 0; i < d_rows; i++) {
615
if (tptr != nilp) tptr[i] = p_time[i];
618
for (long i = d_rows; i < size; i++) {
619
if (tptr != nilp) tptr[i] = Math::M_NAN;
622
// clean old and adjust
636
// get the minimum signed time
638
t_real Rsamples::minst (void) const {
641
t_real result = Math::M_NAN;
642
if (p_time != nilp) {
643
for (long i = 0; i < d_rows; i++) {
644
t_real tval = p_time[i];
645
if (Math::isnan (tval) == true) continue;
646
if ((Math::isnan (result) == true) || (tval < result)) result = tval;
657
// get the maximum signed time
659
t_real Rsamples::maxst (void) const {
662
t_real result = Math::M_NAN;
663
if (p_time != nilp) {
664
for (long i = 0; i < d_rows; i++) {
665
t_real tval = p_time[i];
666
if (Math::isnan (tval) == true) continue;
667
if ((Math::isnan (result) == true) || (tval > result)) result = tval;
678
// get the minimum column value
680
t_real Rsamples::minsc (const long col) const {
683
// check for valid column
684
if ((col < 0) || (col >= d_cols)) {
685
throw Exception ("sample-error", "invalid column position");
687
t_real result = Math::M_NAN;
689
for (long i = 0; i < d_rows; i++) {
690
t_real cval = p_data[i][col];
691
if (Math::isnan (cval) == true) continue;
692
if ((Math::isnan (result) == true) || (cval < result)) result = cval;
703
// get the maximum column value
705
t_real Rsamples::maxsc (const long col) const {
708
// check for valid column
709
if ((col < 0) || (col >= d_cols)) {
710
throw Exception ("sample-error", "invalid column position");
712
t_real result = Math::M_NAN;
713
if (p_data != nilp) {
714
for (long i = 0; i < d_rows; i++) {
715
t_real cval = p_data[i][col];
716
if (Math::isnan (cval) == true) continue;
717
if ((Math::isnan (result) == true) || (cval > result)) result = cval;
728
// smooth the sample array upto a relative error
730
Rsamples* Rsamples::smooth (void) const {
733
Rsamples* result = smooth (Math::d_reps);
742
// smooth the sample array upto a relative error
744
Rsamples* Rsamples::smooth (const t_real reps) const {
746
Rsamples* result = nilp;
748
// check for valid rows
753
// create a result sample array
754
result = new Rsamples (d_cols);
755
result->d_psiz = d_psiz;
756
result->d_sflg = d_sflg;
757
// prepare the working columns
758
t_real time = Math::M_NAN;
760
if (p_time != nilp) time = p_time[0];
761
if (p_data != nilp) {
762
for (long col = 0; col < d_cols; col++) data[col] = p_data[0][col];
765
long rows = d_rows - 1;
766
for (long row = 1; row < rows; row++) {
767
// prepare operating row
768
t_real tval = Math::M_NAN;
770
if (p_time != nilp) tval = p_time[row];
771
if (p_data != nilp) {
772
for (long col = 0; col < d_cols; col++) dval[col] = p_data[row][col];
774
// check for relative error
776
((Math::isnan (time) == true) && (Math::isnan (tval) == true)) ||
777
((Math::isnan (time) != true) && (Math::isnan (tval) != true));
778
for (long col = 0; col < d_cols; col++) {
779
if (Math::rcmp (data[col], dval[col], reps) == false) {
784
// check for data push
785
if (status == false) {
786
long nr = result->newrow (time);
788
for (long col = 0; col < d_cols; col++) {
789
result->p_data[nr][col] = data[col];
790
data[col] = dval[col];
796
time = (p_time == nilp) ? Math::M_NAN : p_time[rows];
797
long nr = result->newrow (time);
798
for (long col = 0; col < d_cols; col++) {
799
result->p_data[nr][col] = p_data[rows][col];
811
// create a print table with the samples
813
PrintTable* Rsamples::toptbl (const bool tflg) const {
815
PrintTable* result = nilp;
817
// compute the effective columns
818
long ecol = (tflg == true) ? d_cols + 1 : d_cols;
819
// create the print table
820
result = (d_rows == 0) ? new PrintTable (ecol) :
821
new PrintTable (ecol, d_rows);
823
Style gstl = result->getstyle ();
824
gstl.setpsiz (d_psiz);
825
gstl.setsflg (d_sflg);
826
result->setstyle (gstl);
827
// loop in the data samples
828
for (long row = 0; row < d_rows; row++) {
829
// create a new row in the table
830
if (result->add () != row) {
831
throw Exception ("internal-error",
832
"inconsistent rsample row index in print-table");
834
// set the time if requested
836
t_real tval = (p_time == nilp) ? Math::M_NAN : p_time[row];
837
result->set (row, 0, tval);
839
for (long col = 0; col < d_cols; col++) {
840
result->set (row, col+1, p_data[row][col]);
844
for (long col = 0; col < d_cols; col++) {
845
result->set (row, col, p_data[row][col]);
859
// -------------------------------------------------------------------------
860
// - object section -
861
// -------------------------------------------------------------------------
864
static const long QUARK_ZONE_LENGTH = 23;
865
static QuarkZone zone (QUARK_ZONE_LENGTH);
867
// the object supported quarks
868
static const long QUARK_SET = zone.intern ("set");
869
static const long QUARK_GET = zone.intern ("get");
870
static const long QUARK_CLEAR = zone.intern ("clear");
871
static const long QUARK_MINST = zone.intern ("min-signed-time");
872
static const long QUARK_MAXST = zone.intern ("max-signed-time");
873
static const long QUARK_MINSC = zone.intern ("min-signed-column");
874
static const long QUARK_MAXSC = zone.intern ("max-signed-column");
875
static const long QUARK_SMOOTH = zone.intern ("smooth");
876
static const long QUARK_NEWROW = zone.intern ("new-row");
877
static const long QUARK_RESIZE = zone.intern ("resize");
878
static const long QUARK_TOPTBL = zone.intern ("to-print-table");
879
static const long QUARK_SETNAME = zone.intern ("set-name");
880
static const long QUARK_SETINFO = zone.intern ("set-info");
881
static const long QUARK_GETINFO = zone.intern ("get-info");
882
static const long QUARK_STAMPED = zone.intern ("stamped-p");
883
static const long QUARK_GETTIME = zone.intern ("get-time");
884
static const long QUARK_GETROWS = zone.intern ("get-rows");
885
static const long QUARK_SETCOLS = zone.intern ("set-columns");
886
static const long QUARK_GETCOLS = zone.intern ("get-columns");
887
static const long QUARK_SETPSIZ = zone.intern ("set-number-precision");
888
static const long QUARK_GETPSIZ = zone.intern ("get-number-precision");
889
static const long QUARK_SETSFLG = zone.intern ("set-scientific-notation");
890
static const long QUARK_GETSFLG = zone.intern ("get-scientific-notation");
892
// create a new object in a generic way
894
Object* Rsamples::mknew (Vector* argv) {
895
long argc = (argv == nilp) ? 0 : argv->length ();
897
// check for 0 argument
898
if (argc == 0) return new Rsamples;
899
// check for 1 argument
901
long cols = argv->getlong (0);
902
return new Rsamples (cols);
905
throw Exception ("argument-error",
906
"invalid arguments with real samples object");
909
// return true if the given quark is defined
911
bool Rsamples::isquark (const long quark, const bool hflg) const {
914
if (zone.exists (quark) == true){
918
bool result = hflg ? Serial::isquark (quark, hflg) : false;
919
if (result == false) {
920
result = hflg ? Nameable::isquark (quark, hflg) : false;
930
// apply this object with a set of arguments and a quark
932
Object* Rsamples::apply (Runnable* robj, Nameset* nset, const long quark,
934
// get the number of arguments
935
long argc = (argv == nilp) ? 0 : argv->length ();
937
// dispatch 0 argument
939
if (quark == QUARK_MINST) return new Real (minst ());
940
if (quark == QUARK_MAXST) return new Real (maxst ());
941
if (quark == QUARK_SMOOTH) return smooth ();
942
if (quark == QUARK_GETINFO) return new String (getinfo ());
943
if (quark == QUARK_GETROWS) return new Integer (getrows ());
944
if (quark == QUARK_GETCOLS) return new Integer (getcols ());
945
if (quark == QUARK_NEWROW) return new Integer (newrow ());
946
if (quark == QUARK_GETPSIZ) return new Integer (getpsiz ());
947
if (quark == QUARK_GETSFLG) return new Boolean (getsflg ());
948
if (quark == QUARK_STAMPED) return new Boolean (stamped ());
949
if (quark == QUARK_TOPTBL) return toptbl (stamped ());
950
if (quark == QUARK_CLEAR) {
955
// dispatch 1 argument
957
if (quark == QUARK_SETNAME) {
958
String name = argv->getstring (0);
962
if (quark == QUARK_SETINFO) {
963
String info = argv->getstring (0);
967
if (quark == QUARK_SETCOLS) {
968
long cols = argv->getlong (0);
972
if (quark == QUARK_NEWROW) {
973
t_real tval = argv->getrint (0);
974
return new Integer (newrow (tval));
976
if (quark == QUARK_RESIZE) {
977
long size = argv->getlong (0);
981
if (quark == QUARK_GETTIME) {
982
long row = argv->getlong (0);
983
return new Real (gettime (row));
985
if (quark == QUARK_TOPTBL) {
986
bool tflg = argv->getbool (0);
987
return toptbl (tflg);
989
if (quark == QUARK_MINSC) {
990
long col = argv->getlong (0);
991
return new Real (minsc (col));
993
if (quark == QUARK_MAXSC) {
994
long col = argv->getlong (0);
995
return new Real (maxsc (col));
997
if (quark == QUARK_SMOOTH) {
998
t_real reps = argv->getreal (0);
999
return smooth (reps);
1001
if (quark == QUARK_SETPSIZ) {
1002
long psiz = argv->getlong (0);
1006
if (quark == QUARK_SETSFLG) {
1007
bool sflg = argv->getbool (0);
1012
// dispatch 2 arguments
1014
if (quark == QUARK_GET) {
1015
long row = argv->getlong (0);
1016
long col = argv->getlong (1);
1017
return new Real (get (row, col));
1020
// dispatch 3 arguments
1022
if (quark == QUARK_SET) {
1023
long row = argv->getlong (0);
1024
long col = argv->getlong (1);
1025
t_real val = argv->getrint (2);
1026
set (row, col, val);
1030
// check the nameable class
1031
if (Nameable::isquark (quark, true) == true) {
1032
return Nameable::apply (robj, nset, quark, argv);
1034
// call the serial object
1035
return Serial::apply (robj, nset, quark, argv);