Statistics
| Branch: | Revision:

root / src / sim / cdensityestbase.cc @ e1750c09

History | View | Annotate | Download (11.8 KB)

1 01873262 Georg Kunz
//=========================================================================
2
//  CDENSITY.CC - part of
3
//
4
//                  OMNeT++/OMNEST
5
//           Discrete System Simulation in C++
6
//
7
//   Member functions of
8
//    cDensityEstBase : common base class for density estimation classes
9
//
10
//   Authors: Andras Varga
11
//
12
//=========================================================================
13
14
/*--------------------------------------------------------------*
15
  Copyright (C) 1992-2008 Andras Varga
16
  Copyright (C) 2006-2008 OpenSim Ltd.
17

18
  This file is distributed WITHOUT ANY WARRANTY. See the file
19
  `license' for details on this and other legal matters.
20
*--------------------------------------------------------------*/
21
22
#include <stdio.h>
23
#include <string.h>
24
#include <math.h>
25
#include <sstream>
26
#include "globals.h"
27
#include "cdensityestbase.h"
28
#include "cexception.h"
29
30
#ifdef WITH_PARSIM
31
#include "ccommbuffer.h"
32
#endif
33
34
USING_NAMESPACE
35
36
using std::ostream;
37
38
39
cDensityEstBase::cDensityEstBase(const char *name) : cStdDev(name)
40
{
41
    range_mode = RANGE_AUTO;
42
    num_firstvals = 100;
43
    range_ext_factor = 2.0;
44
    rangemin = rangemax = 0;
45
    cell_under = cell_over = 0;
46
    transfd = false;
47
    firstvals = new double[num_firstvals];  // to match RANGE_AUTO
48
}
49
50
cDensityEstBase::~cDensityEstBase()
51
{
52
    delete [] firstvals;
53
}
54
55
void cDensityEstBase::parsimPack(cCommBuffer *buffer)
56
{
57
#ifndef WITH_PARSIM
58
    throw cRuntimeError(this, eNOPARSIM);
59
#else
60
    cStdDev::parsimPack(buffer);
61
62
    buffer->pack(rangemin);
63
    buffer->pack(rangemax);
64
    buffer->pack(num_firstvals);
65
    buffer->pack(cell_under);
66
    buffer->pack(cell_over);
67
    buffer->pack(range_ext_factor);
68
    buffer->pack(range_mode);
69
    buffer->pack(transfd);
70
71
    if (buffer->packFlag(firstvals!=NULL))
72
        buffer->pack(firstvals, num_vals); // pack the used positions only
73
#endif
74
}
75
76
void cDensityEstBase::parsimUnpack(cCommBuffer *buffer)
77
{
78
#ifndef WITH_PARSIM
79
    throw cRuntimeError(this, eNOPARSIM);
80
#else
81
    cStdDev::parsimUnpack(buffer);
82
83
    buffer->unpack(rangemin);
84
    buffer->unpack(rangemax);
85
    buffer->unpack(num_firstvals);
86
    buffer->unpack(cell_under);
87
    buffer->unpack(cell_over);
88
    buffer->unpack(range_ext_factor);
89
    buffer->unpack(range_mode);
90
    buffer->unpack(transfd);
91
92
    delete[] firstvals;
93
    firstvals = NULL;
94
    if (buffer->checkFlag())
95
    {
96
        firstvals = new double[num_firstvals];
97
        buffer->unpack(firstvals, num_vals);
98
    }
99
#endif
100
}
101
102
cDensityEstBase& cDensityEstBase::operator=(const cDensityEstBase& res)
103
{
104
    if (this==&res) return *this;
105
106
    cStdDev::operator=(res);
107
108
    rangemin = res.rangemin;
109
    rangemax = res.rangemax;
110
    num_firstvals = res.num_firstvals;
111
    cell_under = res.cell_under;
112
    cell_over = res.cell_over;
113
114
    range_ext_factor = res.range_ext_factor;
115
    range_mode = res.range_mode;
116
117
    transfd = res.transfd;
118
119
    delete [] firstvals;
120
    firstvals = NULL;
121
    if (res.firstvals)
122
    {
123
        firstvals = new double[num_firstvals];
124
        memcpy(firstvals, res.firstvals, num_firstvals*sizeof(double));
125
    }
126
    return *this;
127
}
128
129
void cDensityEstBase::merge(const cStatistic *other)
130
{
131
    if (dynamic_cast<const cDensityEstBase *>(other) == NULL)
132
        throw cRuntimeError(this, "Cannot merge non-histogram (non-cDensityEstBase) statistics (%s)%s into a histogram type",
133
                                  other->getClassName(), other->getFullPath().c_str());
134
135
    const cDensityEstBase *otherd = (const cDensityEstBase *)other;
136
137
    if (!otherd->isTransformed())
138
    {
139
        // easiest and exact solution: simply recollect the observations
140
        // the other object has collected
141
        for (int i=0; i<otherd->num_vals; i++)
142
            collect(firstvals[i]);
143
    }
144
    else
145
    {
146
        // merge the base class
147
        cStdDev::merge(otherd);
148
149
        // force this object to be transformed as well
150
        if (!isTransformed())
151
            transform();
152
153
        // make sure that cells are aligned
154
        if (getNumCells() != otherd->getNumCells())
155
            throw cRuntimeError(this, "Cannot merge (%s)%s: different number of histogram cells (%d vs %d)",
156
                                      otherd->getClassName(), otherd->getFullPath().c_str(), getNumCells(), otherd->getNumCells());
157
        int n = getNumCells();
158
        for (int i=0; i<=n; i++)
159
            if (getBasepoint(i) != otherd->getBasepoint(i))
160
                throw cRuntimeError(this, "Cannot merge (%s)%s: histogram cells are not aligned",
161
                                          otherd->getClassName(), otherd->getFullPath().c_str());
162
163
        // merge underflow/overflow cells
164
        cell_under += otherd->getUnderflowCell(); //FIXME check overflow!! but this is unsigned long....
165
        cell_over += otherd->getOverflowCell();
166
167
        // then merge cell counters
168
        doMergeCellValues(otherd);
169
    }
170
}
171
172
void cDensityEstBase::clearResult()
173
{
174
    cStdDev::clearResult();
175
176
    transfd = false;
177
    range_mode = RANGE_AUTO;
178
    num_firstvals = 100;
179
    range_ext_factor = 2.0;
180
    rangemin = rangemax = 0;
181
    cell_under = cell_over = 0;
182
183
    delete [] firstvals;
184
    firstvals = new double[num_firstvals];  // to match RANGE_AUTO
185
}
186
187
void cDensityEstBase::setRange(double lower, double upper)
188
{
189
    if (num_vals>0 || isTransformed())
190
        throw cRuntimeError(this, "setRange() can only be called before collecting any values");
191
192
    range_mode = RANGE_FIXED;
193
    rangemin = lower;
194
    rangemax = upper;
195
196
    delete [] firstvals;
197
    firstvals = NULL;    // not needed with RANGE_FIXED
198
}
199
200
void cDensityEstBase::setRangeAuto(int num_fstvals, double range_ext_fct)
201
{
202
    if (num_vals>0 || isTransformed())
203
        throw cRuntimeError(this, "setRange...() can only be called before collecting any values");
204
205
    range_mode = RANGE_AUTO;
206
    num_firstvals = num_fstvals;
207
    range_ext_factor = range_ext_fct;
208
209
    delete [] firstvals;
210
    firstvals = new double[num_firstvals];
211
}
212
213
void cDensityEstBase::setRangeAutoLower(double upper, int num_fstvals, double range_ext_fct)
214
{
215
    if (num_vals>0 || isTransformed())
216
        throw cRuntimeError(this, "setRange...() can only be called before collecting any values");
217
218
    range_mode = RANGE_AUTOLOWER;
219
    num_firstvals = num_fstvals;
220
    rangemax = upper;
221
    range_ext_factor = range_ext_fct;
222
223
    delete [] firstvals;
224
    firstvals = new double[num_firstvals];
225
}
226
227
void cDensityEstBase::setRangeAutoUpper(double lower, int num_fstvals, double range_ext_fct)
228
{
229
    if (num_vals>0 || isTransformed())
230
        throw cRuntimeError(this, "setRange...() can only be called before collecting any values");
231
232
    range_mode = RANGE_AUTOUPPER;
233
    num_firstvals = num_fstvals;
234
    rangemin = lower;
235
    range_ext_factor = range_ext_fct;
236
237
    delete [] firstvals;
238
    firstvals = new double[num_firstvals];
239
}
240
241
void cDensityEstBase::setNumFirstVals(int num_fstvals)
242
{
243
    if (num_vals>0 || isTransformed())
244
        throw cRuntimeError(this, "setNumFirstVals() can only be called before collecting any values");
245
246
    num_firstvals = num_fstvals;
247
248
    // if already allocated, reallocate with the correct size
249
    if (firstvals)
250
    {
251
        delete [] firstvals;
252
        firstvals = new double[num_firstvals];
253
    }
254
}
255
256
void cDensityEstBase::setupRange()
257
{
258
    //
259
    // set rangemin and rangemax.
260
    //   Attempts not to make zero width range (makes it 1.0 wide).
261
    //
262
    double c, r;
263
    switch (range_mode)
264
    {
265
      case RANGE_AUTO:
266
         c = (min_vals+max_vals)/2;
267
         r = (max_vals-min_vals)*range_ext_factor;
268
         if (r == 0) r = 1.0; // warning?
269
         rangemin = c-r/2;
270
         rangemax = c+r/2;
271
         break;
272
      case RANGE_AUTOLOWER:
273
         if (rangemax <= min_vals)
274
             rangemin = rangemax-1.0; // warning?
275
         else
276
             rangemin = rangemax-(rangemax-min_vals)*range_ext_factor;
277
         break;
278
      case RANGE_AUTOUPPER:
279
         if (rangemin >= max_vals)
280
             rangemax = rangemin+1.0; // warning?
281
         else
282
             rangemax = rangemin+(max_vals-rangemin)*range_ext_factor;
283
         break;
284
    }
285
}
286
287
void cDensityEstBase::collect(double val)
288
{
289
    if (!isTransformed() && range_mode == RANGE_FIXED)
290
        transform();
291
292
    cStdDev::collect(val); // this also increments num_vals
293
294
    if (!isTransformed())
295
    {
296
        ASSERT(firstvals);
297
        firstvals[num_vals-1] = val;
298
299
        if (num_vals == num_firstvals)
300
            transform();
301
    }
302
    else
303
    {
304
        collectTransformed(val);  // must maintain underflow/overflow cells
305
    }
306
}
307
308
double cDensityEstBase::getCellPDF(int k) const
309
{
310
    if (num_vals == 0) return 0.0;
311
    double cellsize = getBasepoint(k+1) - getBasepoint(k);
312
    return cellsize == 0 ? 0.0 : getCellValue(k)/cellsize/getCount();
313
}
314
315
void cDensityEstBase::plotline(ostream& os, const char *pref, double xval, double count, double a)
316
{
317
    const int picwidth = 54;  // width of picture
318
    char buf[101];
319
    sprintf(buf, "   %s%12f %5g :", pref, xval, count);
320
    char *s = buf+strlen(buf);
321
    int x = (int) floor(a*count+.5);
322
    int k = x<=picwidth ? x : picwidth;
323
    for (int m = 1;  m<=k;  m++)
324
        *s++ = '-';
325
    strcpy(s, x<=picwidth ? "*\n" : ">\n");
326
    os << buf;
327
}
328
329
std::string cDensityEstBase::detailedInfo() const
330
{
331
    std::stringstream os;
332
    os << cStdDev::detailedInfo();
333
334
    if (!isTransformed())
335
    {
336
        ASSERT(firstvals || num_vals==0);
337
        os << "Values collected so far: ";
338
        for (int i=0; i<num_vals; i++)
339
            os << (i==0?"":", ") << firstvals[i];
340
        os << "\n";
341
    }
342
    else
343
    {
344
        // transformed
345
        const int picwidth = 55;   // width of picture
346
        double max = 0;            // biggest cell value
347
        int nc = getNumCells();    // number of cells
348
        int k;
349
        double d;
350
        for (k = 0; k<nc; k++)
351
            if ((d = getCellValue(k)) > max)
352
                max = d;
353
        double a = (double)picwidth/max;
354
355
        os << "Distribution density function:\n";
356
        for (k = 0; k<nc; k++)
357
            plotline(os, "< ", getBasepoint(k), (k==0 ? cell_under : getCellValue(k-1)), a);
358
        plotline(os, ">=", getBasepoint(nc), cell_over, a);
359
        os << "\n";
360
    }
361
    return os.str();
362
}
363
364
void cDensityEstBase::saveToFile(FILE *f) const
365
{
366
    cStdDev::saveToFile(f);
367
368
    fprintf(f, "%d\t #= transformed\n", transfd);
369
    fprintf(f, "%d\t #= range_mode\n", range_mode);
370
    fprintf(f, "%g\t #= range_ext_factor\n", range_ext_factor);
371
    fprintf(f, "%g %g\t #= range\n", rangemin, rangemax);
372
    fprintf(f, "%lu %lu\t #= cell_under, cell_over\n", cell_under, cell_over);
373
    fprintf(f, "%d\t #= num_firstvals\n", num_firstvals);
374
375
    fprintf(f, "%d\t #= firstvals[] exists\n", firstvals!=NULL);
376
    if (firstvals)
377
        for (int i=0; i<num_vals; i++)
378
            fprintf(f, " %g\n", firstvals[i]);
379
}
380
381
void cDensityEstBase::loadFromFile(FILE *f)
382
{
383
    cStdDev::loadFromFile(f);
384
385
    freadvarsf(f, "%d\t #= transformed", &transfd);
386
    freadvarsf(f, "%d\t #= range_mode", &range_mode);
387
    freadvarsf(f, "%g\t #= range_ext_factor", &range_ext_factor);
388
    freadvarsf(f, "%g %g\t #= range", &rangemin, &rangemax);
389
    freadvarsf(f, "%lu %lu\t #= cell_under, cell_over", &cell_under, &cell_over);
390
    freadvarsf(f, "%ld\t #= num_firstvals", &num_firstvals);
391
392
    int firstvals_exists;
393
    freadvarsf(f, "%d\t #= firstvals[] exists", &firstvals_exists);
394
395
    delete [] firstvals;
396
    firstvals = NULL;
397
    if (firstvals_exists)
398
    {
399
        firstvals = new double[num_firstvals];
400
        for (int i=0; i<num_vals; i++)
401
            freadvarsf(f, " %g", firstvals+i);
402
    }
403
}
404
405
cDensityEstBase::Cell cDensityEstBase::getCellInfo(int k) const
406
{
407
    if (k<0 || k>=getNumCells())
408
        return Cell();
409
    Cell c;
410
    c.lower = getBasepoint(k);
411
    c.upper = getBasepoint(k+1);
412
    c.value = getCellValue(k);
413
    c.relativeFreq = getCellPDF(k);
414
    return c;
415
}
416
417
const cDensityEstBase::Cell& cDensityEstBase::internalGetCellInfo(int k) const
418
{
419
    // only for use in sim_std.msg (each call overwrites the static buffer!)
420
    static Cell buf;
421
    buf = getCellInfo(k);
422
    return buf;
423
}