## root / src / sim / chistogram.cc @ 08285dff

History | View | Annotate | Download (11.9 KB)

1 | 01873262 | Georg Kunz | ```
//=========================================================================
``` |
---|---|---|---|

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 : equi-distant histogram
``` |
||

10 | ```
// cLongHistogram : long integer histogram
``` |
||

11 | ```
// cDoubleHistogram : double histogram
``` |
||

12 | ```
//
``` |
||

13 | ```
// Authors: Andras Varga, Gabor Lencse
``` |
||

14 | ```
//
``` |
||

15 | ```
//=========================================================================
``` |
||

16 | |||

17 | ```
/*--------------------------------------------------------------*
``` |
||

18 | ```
Copyright (C) 1992-2008 Andras Varga
``` |
||

19 | ```
Copyright (C) 2006-2008 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)(rangemax-rangemin); |
||

288 | |||

289 | if (num_cells>0 && cellsize>0) { |
||

290 | ```
if (num_cells*cellsize != range)
``` |
||

291 | throw cRuntimeError(this, COMPLAINT": numCells*cellSize != rangeMax-rangeMin"); |
||

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 equal-sized cells"); |
||

311 | num_cells = range / cellsize; |
||

312 | } |
||

313 | ```
#undef COMPLAINT
``` |
||

314 | } |
||

315 | ```
else
``` |
||

316 | { |
||

317 | ```
// non-fixed 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((rangemax-rangemin)/num_cells);
``` |
||

324 | } |
||

325 | else if (cellsize>0) { |
||

326 | ```
// cellsize given ==> choose num_cells
``` |
||

327 | ```
num_cells = (int) ceil((rangemax-rangemin)/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 - (rangemax-rangemin);
``` |
||

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 post-processing |
||

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 (k-1) 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: integer-valued doubles (e.g.: -3.0, 5.0)
``` |
||

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

390 | ```
// cellsize: integer-valued double, >0
``` |
||

391 | return ceil(rangemin) + (k-1)*(long)cellsize + genk_intrand(genk, (long)cellsize); |
||

392 | } |
||

393 | ```
else
``` |
||

394 | { |
||

395 | ```
// return an uniform double from the given cell
``` |
||

396 | return rangemin + (k-1)*cellsize + genk_dblrand(genk)*cellsize; |
||

397 | } |
||

398 | } |
||

399 | } |
||

400 | |||

401 | void cHistogram::collectTransformed (double val) |
||

402 | { |
||

403 | int k = (int)floor((val-rangemin)/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((x-rangemin)/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 |