root / src / sim / chistogram.cc @ 08285dff
History  View  Annotate  Download (11.9 KB)
1 
//=========================================================================


2 
// CHISTOGRAM.CC  part of

3 
//

4 
// OMNeT++/OMNEST

5 
// Discrete System Simulation in C++

6 
//

7 
// Member functions of

8 
// cHistogramBase : common base class for histogram classes

9 
// cHistogram : equidistant histogram

10 
// cLongHistogram : long integer histogram

11 
// cDoubleHistogram : double histogram

12 
//

13 
// Authors: Andras Varga, Gabor Lencse

14 
//

15 
//=========================================================================

16  
17 
/**

18 
Copyright (C) 19922008 Andras Varga

19 
Copyright (C) 20062008 OpenSim Ltd.

20 

21 
This file is distributed WITHOUT ANY WARRANTY. See the file

22 
`license' for details on this and other legal matters.

23 
**/

24  
25 
#include <stdio.h> 
26 
#include <stdlib.h> 
27 
#include <string.h> 
28 
#include <math.h> 
29 
#include "random.h" 
30 
#include "distrib.h" 
31 
#include "globals.h" 
32 
#include "cdetect.h" 
33 
#include "chistogram.h" 
34 
#include "cexception.h" 
35 
#include "cenvir.h" 
36  
37 
#ifdef WITH_PARSIM

38 
#include "ccommbuffer.h" 
39 
#endif

40  
41 
USING_NAMESPACE 
42  
43 
#define MIN(a,b) ((a)<(b) ? (a) : (b))

44 
#define MAX(a,b) ((a)>(b) ? (a) : (b))

45  
46  
47 
Register_Class(cLongHistogram); 
48 
Register_Class(cDoubleHistogram); 
49  
50  
51 
cHistogramBase::cHistogramBase(const char *name, int numcells) : 
52 
cDensityEstBase(name) 
53 
{ 
54 
cellv = NULL;

55 
num_cells = numcells; 
56 
} 
57  
58 
cHistogramBase::~cHistogramBase() 
59 
{ 
60 
delete [] cellv;

61 
} 
62  
63 
void cHistogramBase::parsimPack(cCommBuffer *buffer)

64 
{ 
65 
#ifndef WITH_PARSIM

66 
throw cRuntimeError(this, eNOPARSIM); 
67 
#else

68 
cDensityEstBase::parsimPack(buffer); 
69 
buffer>pack(num_cells); 
70  
71 
if (buffer>packFlag(cellv!=NULL)) 
72 
buffer>pack(cellv, num_cells); 
73 
#endif

74 
} 
75  
76 
void cHistogramBase::parsimUnpack(cCommBuffer *buffer)

77 
{ 
78 
#ifndef WITH_PARSIM

79 
throw cRuntimeError(this, eNOPARSIM); 
80 
#else

81 
cDensityEstBase::parsimUnpack(buffer); 
82 
buffer>pack(num_cells); 
83  
84 
if (buffer>checkFlag())

85 
{ 
86 
cellv = new unsigned int[num_cells]; 
87 
buffer>unpack(cellv, num_cells); 
88 
} 
89 
#endif

90 
} 
91  
92 
cHistogramBase& cHistogramBase::operator=(const cHistogramBase& res) 
93 
{ 
94 
if (this==&res) return *this; 
95  
96 
cDensityEstBase::operator=(res);

97  
98 
num_cells = res.num_cells; 
99 
delete [] cellv;

100 
cellv = NULL;

101 
if (res.cellv)

102 
{ 
103 
cellv = new unsigned[num_cells]; 
104 
memcpy(cellv, res.cellv, num_cells*sizeof(unsigned)); 
105 
} 
106 
return *this; 
107 
} 
108  
109 
void cHistogramBase::doMergeCellValues(const cDensityEstBase *other) 
110 
{ 
111 
for (int i=0; i<num_cells; i++) 
112 
cellv[i] += (unsigned int) other>getCellValue(i); //TODO overflow check 
113 
} 
114  
115 
void cHistogramBase::clearResult()

116 
{ 
117 
cDensityEstBase::clearResult(); 
118  
119 
delete [] cellv;

120 
cellv = NULL;

121 
} 
122  
123 
void cHistogramBase::transform()

124 
{ 
125 
if (isTransformed())

126 
throw cRuntimeError(this, "transform(): histogram already transformed"); 
127  
128 
setupRange(); // this will set num_cells if it was unspecified (1)

129  
130 
int i;

131 
cellv = new unsigned [num_cells]; 
132 
for (i=0; i<num_cells; i++) 
133 
cellv[i] = 0;

134  
135 
for (i=0; i<num_vals; i++) 
136 
collectTransformed(firstvals[i]); 
137  
138 
delete [] firstvals;

139 
firstvals = NULL;

140  
141 
transfd = true;

142 
} 
143  
144 
int cHistogramBase::getNumCells() const 
145 
{ 
146 
if (!isTransformed())

147 
return 0; 
148 
return num_cells;

149 
} 
150  
151 
void cHistogramBase::saveToFile(FILE *f) const 
152 
{ 
153 
cDensityEstBase::saveToFile(f); 
154 
fprintf(f, "%d\t #= num_cells\n", num_cells);

155 
fprintf(f, "%d\t #= cellv[] exists\n", cellv!=NULL); 
156 
if (cellv) for (int i=0; i<num_cells; i++) fprintf(f, " %u\n", cellv[i]); 
157 
} 
158  
159 
void cHistogramBase::loadFromFile(FILE *f)

160 
{ 
161 
cDensityEstBase::loadFromFile(f); 
162 
freadvarsf(f, "%d\t #= num_cells", &num_cells);

163  
164 
int cellv_exists;

165 
freadvarsf(f, "%d\t #= cellv[] exists", &cellv_exists);

166 
delete [] cellv; cellv = NULL; 
167 
if (cellv_exists)

168 
{ 
169 
cellv = new unsigned[num_cells]; 
170 
for (int i=0; i<num_cells; i++) freadvarsf(f, " %u", cellv+i); 
171 
} 
172 
} 
173  
174 
void cHistogramBase::setNumCells(int numcells) 
175 
{ 
176 
if (cellv)

177 
throw cRuntimeError(this, "setNumCells(): too late, cells already set up"); 
178 
num_cells = numcells; 
179 
} 
180  
181  
182 
//

183 
// cHistogram  member functions

184  
185 
cHistogram::cHistogram(const char *name, int numcells, Mode mode) : 
186 
cHistogramBase(name, numcells) 
187 
{ 
188 
cellsize = 0;

189 
this>mode = mode;

190 
} 
191  
192 
void cHistogram::parsimPack(cCommBuffer *buffer)

193 
{ 
194 
#ifndef WITH_PARSIM

195 
throw cRuntimeError(this, eNOPARSIM); 
196 
#else

197 
cHistogramBase::parsimPack(buffer); 
198 
buffer>pack(cellsize); 
199 
#endif

200 
} 
201  
202 
void cHistogram::parsimUnpack(cCommBuffer *buffer)

203 
{ 
204 
#ifndef WITH_PARSIM

205 
throw cRuntimeError(this, eNOPARSIM); 
206 
#else

207 
cHistogramBase::parsimUnpack(buffer); 
208 
buffer>unpack(cellsize); 
209 
#endif

210 
} 
211  
212 
cHistogram& cHistogram::operator = (const cHistogram& res) 
213 
{ 
214 
if (this==&res) return *this; 
215  
216 
cHistogramBase::operator=(res);

217 
cellsize = res.cellsize; 
218 
mode = res.mode; 
219 
return *this; 
220 
} 
221  
222 
void cHistogram::setMode(Mode mode)

223 
{ 
224 
if (isTransformed())

225 
throw cRuntimeError(this, "setMode() cannot be called when cells have been set up already"); 
226 
this>mode = mode;

227 
} 
228  
229 
void cHistogram::setCellSize(double d) 
230 
{ 
231 
if (isTransformed())

232 
throw cRuntimeError(this, "setCellSize() cannot be called when cells have been set up already"); 
233 
cellsize = d; 
234 
} 
235  
236 
void cHistogram::getAttributesToRecord(opp_string_map& attributes)

237 
{ 
238 
cHistogramBase::getAttributesToRecord(attributes); 
239  
240 
if (mode == MODE_INTEGERS)

241 
attributes["type"] = "int"; 
242 
} 
243  
244 
void cHistogram::setupRange()

245 
{ 
246 
cHistogramBase::setupRange(); 
247  
248 
// the following code sets num_cells, and cellsize as (rangemax  rangemin) / num_cells

249  
250 
if (mode == MODE_AUTO)

251 
{ 
252 
// if all precollected numbers are integers (and they are not all zeroes), go for integer mode

253 
bool allzeroes = true; 
254 
bool allints = true; 
255 
for (int i=0; i < num_vals; i++) 
256 
{ 
257 
if (firstvals[i] != 0) 
258 
allzeroes = false;

259 
if (firstvals[i] != floor(firstvals[i]))

260 
allints = false;

261 
} 
262  
263 
mode = (num_vals > 0 && allints && !allzeroes) ? MODE_INTEGERS : MODE_DOUBLES;

264 
} 
265  
266 
if (mode == MODE_INTEGERS)

267 
setupRangeInteger(); 
268 
else

269 
setupRangeDouble(); 
270 
} 
271  
272 
void cHistogram::setupRangeInteger()

273 
{ 
274 
// set up the missing ones of: rangemin, rangemax, num_cells, cellsize;

275 
// throw error if not everything can be set up consistently

276  
277 
// cellsize is double but we want to calculate with integers here

278 
long cellsize = (long) this>cellsize; 
279  
280 
// convert range limits to integers

281 
rangemin = floor(rangemin); 
282 
rangemax = ceil(rangemax); 
283  
284 
if (range_mode == RANGE_FIXED)

285 
{ 
286 
#define COMPLAINT "Cannot set up cells to satisfy constraints" 
287 
long range = (long)(rangemaxrangemin); 
288  
289 
if (num_cells>0 && cellsize>0) { 
290 
if (num_cells*cellsize != range)

291 
throw cRuntimeError(this, COMPLAINT": numCells*cellSize != rangeMaxrangeMin"); 
292 
} 
293 
else if (cellsize>0) { 
294 
if (range % cellsize != 0) 
295 
throw cRuntimeError(this, COMPLAINT": specified range is not a multiple of cellSize"); 
296 
num_cells = range / cellsize; 
297 
} 
298 
else if (num_cells>0) { 
299 
if (range % num_cells != 0) 
300 
throw cRuntimeError(this, COMPLAINT": specified range is not a multiple of numCells"); 
301 
cellsize = range / num_cells; 
302 
} 
303 
else {

304 
int mincellsize = (int) ceil(range/200.0); 
305 
int maxcellsize = (int) ceil(range/10.0); 
306 
for (cellsize = mincellsize; cellsize <= maxcellsize; cellsize++)

307 
if (range % cellsize == 0) 
308 
break;

309 
if (cellsize > maxcellsize)

310 
throw cRuntimeError(this, COMPLAINT": specified range is too large, and cannot divide it to 10..200 equalsized cells"); 
311 
num_cells = range / cellsize; 
312 
} 
313 
#undef COMPLAINT

314 
} 
315 
else

316 
{ 
317 
// nonfixed range

318 
if (num_cells>0 && cellsize>0) { 
319 
// both given; num_cells*cellsize will determine the range

320 
} 
321 
else if (num_cells>0) { 
322 
// num_cells given ==> choose cellsize

323 
cellsize = (long) ceil((rangemaxrangemin)/num_cells);

324 
} 
325 
else if (cellsize>0) { 
326 
// cellsize given ==> choose num_cells

327 
num_cells = (int) ceil((rangemaxrangemin)/cellsize);

328 
} 
329 
else {

330 
// neither given, choose both

331 
double range = rangemax  rangemin;

332 
cellsize = (long) ceil(range / 200.0); // for range<=200, cellsize==1 
333 
num_cells = (int) ceil(range/cellsize);

334 
} 
335  
336 
// adjust range to be cellsize*num_cells

337 
double newrange = cellsize*num_cells;

338 
double rangediff = newrange  (rangemaxrangemin);

339  
340 
switch (range_mode)

341 
{ 
342 
case RANGE_AUTO:

343 
rangemin = floor(rangediff/2);

344 
rangemax = rangemin + newrange; 
345 
break;

346 
case RANGE_AUTOLOWER:

347 
rangemin = rangemax  newrange; 
348 
break;

349 
case RANGE_AUTOUPPER:

350 
rangemax = rangemin + newrange; 
351 
break;

352 
} 
353 
} 
354  
355 
// write back the integer cellsize into double

356 
this>cellsize = cellsize;

357 
} 
358  
359 
void cHistogram::setupRangeDouble()

360 
{ 
361 
if (num_cells == 1) 
362 
num_cells = 30; // to allow merging every 2, 3, 5, 6 adjacent cells in postprocessing 
363 
cellsize = (rangemax  rangemin) / num_cells; 
364 
} 
365  
366 
double cHistogram::random() const 
367 
{ 
368 
if (num_vals == 0) 
369 
{ 
370 
return 0L; 
371 
} 
372 
else if (num_vals < num_firstvals) 
373 
{ 
374 
// randomly select a sample from the stored ones

375 
return firstvals[genk_intrand(genk, num_vals)];

376 
} 
377 
else

378 
{ 
379 
long m = genk_intrand(genk, num_vals  cell_under  cell_over);

380  
381 
// select a random cell (k1) and return a random number from it

382 
int k;

383 
for (k = 0; m >= 0; k++) 
384 
m = cellv[k]; 
385  
386 
if (mode == MODE_INTEGERS)

387 
{ 
388 
// min_vals, max_vals: integervalued doubles (e.g.: 3.0, 5.0)

389 
// rangemin, rangemax: doubles like 1.5, 4.5 (integer+0.5)

390 
// cellsize: integervalued double, >0

391 
return ceil(rangemin) + (k1)*(long)cellsize + genk_intrand(genk, (long)cellsize); 
392 
} 
393 
else

394 
{ 
395 
// return an uniform double from the given cell

396 
return rangemin + (k1)*cellsize + genk_dblrand(genk)*cellsize; 
397 
} 
398 
} 
399 
} 
400  
401 
void cHistogram::collectTransformed (double val) 
402 
{ 
403 
int k = (int)floor((valrangemin)/cellsize); 
404 
if (k < 0  val < rangemin) 
405 
cell_under++; 
406 
else if (k >= num_cells  val >= rangemax) 
407 
cell_over++; 
408 
else

409 
cellv[k]++; 
410 
} 
411  
412 
double cHistogram::getPDF(double x) const 
413 
{ 
414 
if (!isTransformed())

415 
throw cRuntimeError(this, "getPDF(x) cannot be called before histogram is transformed"); 
416  
417 
int k = (int)floor((xrangemin)/cellsize); 
418 
if (k < 0  x < rangemin  k >= num_cells  x >= rangemax) 
419 
return 0.0; 
420  
421 
return cellv[k] / cellsize / num_vals;

422 
} 
423  
424 
double cHistogram::getCDF(double) const 
425 
{ 
426 
throw cRuntimeError(this, "getCDF() not implemented"); 
427 
} 
428  
429 
// return kth basepoint

430 
double cHistogram::getBasepoint(int k) const 
431 
{ 
432 
// k=0 : rangemin

433 
// k=1,2,... : rangemin + k*cellsize

434 
// k=num_cells : rangemax

435  
436 
if (k<0  k>num_cells) 
437 
throw cRuntimeError(this, "invalid basepoint index %u", k); 
438  
439 
if (k == num_cells)

440 
return rangemax;

441 
else

442 
return rangemin + k*cellsize;

443 
} 
444  
445 
double cHistogram::getCellValue(int k) const 
446 
{ 
447 
if (k<0  k>num_cells) 
448 
throw cRuntimeError(this, "invalid cell index %u", k); 
449 
return cellv[k];

450 
} 
451  
452 
void cHistogram::saveToFile(FILE *f) const 
453 
{ 
454 
cHistogramBase::saveToFile(f); 
455 
fprintf(f, "%g\t #= cellsize\n", cellsize);

456 
} 
457  
458 
void cHistogram::loadFromFile(FILE *f)

459 
{ 
460 
cHistogramBase::loadFromFile(f); 
461 
freadvarsf(f, "%g\t #= cellsize", &cellsize);

462 
} 
463  
464 