1 /* simmonte.c
2
3 Copyright (c) 1993-2017 Free Software Foundation, Inc.
4
5 This file is part of GNU MCSim.
6
7 GNU MCSim is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 3
10 of the License, or (at your option) any later version.
11
12 GNU MCSim is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU MCSim; if not, see <http://www.gnu.org/licenses/>
19
20 Handles functions related to Monte Carlo analysis.
21
22 */
23
24 #include <assert.h>
25 #include <ctype.h>
26 #include <float.h>
27 #include <math.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "sim.h"
32 #include "lex.h"
33 #include "lexerr.h"
34 #include "strutil.h"
35 #include "simmonte.h"
36
37
38 /* ----------------------------------------------------------------------------
39 SetParms
40
41 sets the parameters in the rghvar array to the values in the rgdParm
42 array.
43 */
SetParms(long cParms,HVAR * rghvar,double * rgdParm)44 void SetParms (long cParms, HVAR *rghvar, double *rgdParm)
45 {
46 long i;
47
48 for (i = 0; i < cParms; i++)
49 SetVar (rghvar[i], rgdParm[i]);
50
51 } /* SetParms */
52
53
54 /* ----------------------------------------------------------------------------
55 SetParmsLog
56
57 sets the parameters in the rghvar array to the log-transformed
58 values in the rgdParm array.
59 */
SetParmsLog(long cParms,HVAR * rghvar,double * rgdParm)60 void SetParmsLog (long cParms, HVAR *rghvar, double *rgdParm)
61 {
62 long i;
63
64 for (i = 0; i < cParms; i++)
65 SetVar (rghvar[i], log(rgdParm[i]));
66
67 } /* SetParmsLog */
68
69
70 /* ----------------------------------------------------------------------------
71 SetParmsExp
72
73 sets the parameters in the rghvar array to the exp-transformed
74 values in the rgdParm array.
75 */
SetParmsExp(long cParms,HVAR * rghvar,double * rgdParm)76 void SetParmsExp (long cParms, HVAR *rghvar, double *rgdParm)
77 {
78 long i;
79
80 for (i = 0; i < cParms; i++)
81 SetVar (rghvar[i], exp(rgdParm[i]));
82
83 } /* SetParmsExp */
84
85
86 /* ----------------------------------------------------------------------------
87 CalculateOneMCParm
88
89 Callback function for CalculateMCParms. Assign the dVal member of
90 a MCVAR structure by sampling from the distribution specified by its iType
91 */
CalculateOneMCParm(PMCVAR pMCVar)92 int CalculateOneMCParm (PMCVAR pMCVar)
93 {
94 double dParm1, dParm2, dMin, dMax;
95
96 /* Check pMCVar for dependencies */
97 dParm1 = *(pMCVar->pdParm[0]);
98 dParm2 = *(pMCVar->pdParm[1]);
99 dMin = *(pMCVar->pdParm[2]);
100 dMax = *(pMCVar->pdParm[3]);
101
102 /* Set variable randomly according to selected distribution */
103 switch (pMCVar->iType) {
104
105 default:
106 case MCV_UNIFORM:
107 pMCVar->dVal = UniformRandom(dParm1, dParm2);
108 break;
109
110 case MCV_LOGUNIFORM:
111 pMCVar->dVal = LogUniformRandom(dParm1, dParm2);
112 break;
113
114 case MCV_BETA:
115 pMCVar->dVal = BetaRandom(dParm1, dParm2, dMin, dMax);
116 break;
117
118 case MCV_HALFNORMAL:
119 pMCVar->dVal = fabs(NormalRandom(dParm1, dParm2));
120 break;
121
122 case MCV_NORMAL:
123 pMCVar->dVal = NormalRandom(dParm1, dParm2);
124 break;
125
126 case MCV_NORMALCV:
127 pMCVar->dVal = NormalRandom(dParm1, fabs(dParm1 * dParm2));
128 break;
129
130 case MCV_NORMALV:
131 pMCVar->dVal = NormalRandom(dParm1, sqrt(dParm2));
132 break;
133
134 case MCV_TRUNCNORMAL:
135 pMCVar->dVal = TruncNormalRandom(dParm1, dParm2, dMin, dMax);
136 break;
137
138 case MCV_TRUNCNORMALCV:
139 pMCVar->dVal = TruncNormalRandom(dParm1, fabs(dParm1 * dParm2),
140 dMin, dMax);
141 break;
142
143 case MCV_TRUNCNORMALV:
144 pMCVar->dVal = TruncNormalRandom(dParm1, sqrt(dParm2), dMin, dMax);
145 break;
146
147 case MCV_LOGNORMAL:
148 pMCVar->dVal = LogNormalRandom(dParm1, dParm2);
149 break;
150
151 case MCV_TRUNCLOGNORMAL:
152 pMCVar->dVal = TruncLogNormalRandom(dParm1, dParm2, dMin, dMax);
153 break;
154
155 case MCV_LOGNORMALV:
156 pMCVar->dVal = LogNormalRandom(dParm1, exp(sqrt(dParm2)));
157 break;
158
159 case MCV_TRUNCLOGNORMALV:
160 pMCVar->dVal = TruncLogNormalRandom(dParm1, exp(sqrt(dParm2)),
161 dMin, dMax);
162 break;
163
164 case MCV_CHI2:
165 pMCVar->dVal = Chi2Random(dParm1);
166 break;
167
168 case MCV_BINOMIAL:
169 pMCVar->dVal = BinomialRandom(dParm1, (long) dParm2);
170 break;
171
172 case MCV_PIECEWISE:
173 pMCVar->dVal = PiecewiseRandom(dMin, dParm1, dParm2, dMax);
174 break;
175
176 case MCV_EXPONENTIAL:
177 pMCVar->dVal = ExpRandom(dParm1);
178 break;
179
180 case MCV_GGAMMA:
181 pMCVar->dVal = GGammaRandom(dParm1, dParm2);
182 break;
183
184 case MCV_INVGGAMMA:
185 pMCVar->dVal = InvGGammaRandom(dParm1, dParm2);
186 break;
187
188 case MCV_TRUNCINVGGAMMA:
189 pMCVar->dVal = TruncInvGGammaRandom(dParm1, dParm2, dMin, dMax);
190 break;
191
192 case MCV_POISSON:
193 pMCVar->dVal = PoissonRandom(dParm1);
194 break;
195
196 case MCV_BINOMIALBETA: /* dMin is in fact beta */
197 pMCVar->dVal = BinomialBetaRandom(dParm1, dParm2, dMin);
198 break;
199
200 case MCV_GENLOGNORMAL: /* dMin is in fact stdevlognorm */
201 pMCVar->dVal = GenLogNormalRandom(dParm1, dParm2, dMin);
202 break;
203
204 case MCV_STUDENTT: /* dMin is in fact the scale parameter */
205 pMCVar->dVal = StudentTRandom(dParm1, dParm2, dMin);
206 break;
207
208 case MCV_CAUCHY:
209 pMCVar->dVal = CauchyRandom(dParm1);
210 break;
211
212 case MCV_HALFCAUCHY:
213 pMCVar->dVal = fabs(CauchyRandom(dParm1));
214 break;
215
216 case MCV_USERLL: /* not allowed for straight Monte Carlo simulations */
217 ReportError (NULL, RE_BADCONTEXT | RE_FATAL, "UserSpecifiedLL", NULL);
218 break;
219
220 case MCV_NEGATIVEBINOM:
221 pMCVar->dVal = NegativeBinomialRandom(dParm1, dParm2);
222 break;
223
224 } /* switch */
225
226 return 0;
227
228 } /* CalculateOneMCParm */
229
230
231 /* ----------------------------------------------------------------------------
232 CalcMCParms
233
234 calculates random parameters for a Monte Carlo variation.
235
236 This routines uses arrays for the MC vars and distributions.
237 It replaces the obsolete CalculateMCParms which used lists.
238
239 The calculated parms are stored in the rgParms[] array. If this
240 array is NULL, the parms are stored in the pMC->rgParms[] array.
241
242 The calculation starts at index iStart.
243 */
CalcMCParms(PMONTECARLO pMC,double rgParms[],long iStart)244 void CalcMCParms (PMONTECARLO pMC, double rgParms[], long iStart)
245 {
246 long i;
247
248 if (!rgParms)
249 rgParms = pMC->rgdParms; /* Put them in the usual place */
250
251 for (i = iStart; i < pMC->nParms; i++) {
252 CalculateOneMCParm (pMC->rgpMCVar[i]);
253 rgParms[i] = pMC->rgpMCVar[i]->dVal;
254 } /* for */
255
256 } /* CalcMCParms */
257
258
259 /* ----------------------------------------------------------------------------
260 InitSetPoints
261
262 Openn and reads the header of the SetPoint file containing the
263 parameters to be tried.
264
265 Returns the file pointer if everything is ok.
266 */
InitSetPoints(PMONTECARLO pMC)267 BOOL InitSetPoints (PMONTECARLO pMC)
268 {
269 register char c;
270 PFILE pfile;
271
272 if (!(pfile = fopen(pMC->szSetPointsFilename, "r")))
273 ReportError (NULL, RE_CANNOTOPEN | RE_FATAL,
274 pMC->szSetPointsFilename, NULL);
275
276 pMC->pfileSetPoints = pfile;
277
278 /* Throw away the first line. This allows a MC output file to be used
279 directly as a setpoints file. */
280 do { c = getc(pMC->pfileSetPoints); } while (c != '\n');
281
282 if (feof(pMC->pfileSetPoints))
283 ReportError (NULL, RE_INSUF_POINTS | RE_FATAL,
284 pMC->szSetPointsFilename, NULL);
285
286 return (!pfile);
287
288 } /* InitSetPoints */
289
290
291 /* ----------------------------------------------------------------------------
292 ReadSetPoints
293
294 Reads set points from a file for this run.
295
296 Returns non-zero if a full set of points is read, 0 otherwise.
297 */
ReadSetPoints(PMONTECARLO pMC,double rgParms[])298 BOOL ReadSetPoints (PMONTECARLO pMC, double rgParms[])
299 {
300 BOOL bReturn = FALSE; /* Initially, flag no points read */
301 register char c;
302 long i;
303
304 if (!rgParms)
305 rgParms = pMC->rgdParms; /* Put data in the usual place */
306
307 /* Throw away dummy field */
308 do {
309 c = getc(pMC->pfileSetPoints);
310 if (feof(pMC->pfileSetPoints))
311 goto Exit_ReadSetPoints;
312 } while ((c != '\t') && (c != ' '));
313
314 /* Increment across set point parms list */
315 for (i = 0; i < pMC->nSetParms; i++) {
316
317 /* Try to read one data point */
318 if (feof(pMC->pfileSetPoints) ||
319 (fscanf(pMC->pfileSetPoints, "%lg", &pMC->rgpMCVar[i]->dVal) == EOF)) {
320
321 if (pMC->nRuns) /* More points expected */
322 ReportError (NULL, RE_INSUF_POINTS | RE_FATAL,
323 pMC->szSetPointsFilename, NULL);
324
325 /* If !nRuns, flag that EOF reached without issuing error */
326 goto Exit_ReadSetPoints;
327
328 } /* if */
329
330 rgParms[i] = pMC->rgpMCVar[i]->dVal; /* Copy value to user array */
331 } /* for */
332
333 bReturn = TRUE; /* Flag that all parms were read */
334
335 /* Throw away remainder of line. This allows a MC output file to be used
336 directly as a setpoints file. */
337 do {
338 c = getc(pMC->pfileSetPoints);
339 } while ((c != '\n') && !feof(pMC->pfileSetPoints));
340
341 Exit_ReadSetPoints:
342 ;
343 return (bReturn);
344
345 } /* ReadSetPoints */
346
347
348 /* ----------------------------------------------------------------------------
349 GetSPMods
350
351 Reads a new set of modifications from the set points input file.
352
353 Returns TRUE if got modifications OK.
354
355 FALSE is only returned when the number of runs (nRuns) is set to
356 zero. In this case the simulation continues until end of file is
357 reached, and returns FALSE to flag the eof condition.
358 */
GetSPMods(PANALYSIS panal,double rgParms[])359 BOOL GetSPMods (PANALYSIS panal, double rgParms[])
360 {
361 BOOL bOK;
362
363 bOK = ReadSetPoints (&panal->mc, rgParms);
364 /* eventually override by Distrib specs */
365 CalcMCParms (&panal->mc, rgParms, panal->mc.nSetParms);
366 return bOK;
367
368 } /* GetSPMods */
369
370
371 /* ----------------------------------------------------------------------------
372 SetParents
373
374 FB 21/07/97: For each Monte Carlo variable, if there are parents referenced
375 in hParm for some of the distributional parameters, pdParms are set to point
376 to the parent's dVals. If there is no parent, pdParms already point to their
377 own dParms and nothing is done.
378
379 The calculation starts at index iStart.
380 */
SetParents(PMONTECARLO pMC,long iStart)381 void SetParents (PMONTECARLO pMC, long iStart)
382 {
383 long i, j, k;
384 PMCVAR pMCVar1, pMCVar2;
385 BOOL bFound;
386
387 for (i = iStart; i < pMC->nParms; i++) { /* for each pMCVar considered */
388 pMCVar1 = pMC->rgpMCVar[i];
389 for (j = 0; j < 4; j++) { /* for each of its distrib. param */
390 if (pMCVar1->iParmType[j] == MCVP_PARM) {
391 /* if there is a parent, find it, but parents must appear before
392 current pMCVar */
393 bFound = FALSE;
394 for (k = 0; k < i; k++) {
395 pMCVar2 = pMC->rgpMCVar[k];
396 if (pMCVar1->hParm[j] == pMCVar2->hvar) {
397 /* Point to the parent dVal */
398 pMCVar1->pdParm[j] = &(pMCVar2->dVal);
399 bFound = TRUE;
400 }
401 }
402 if (!bFound) { /* oops, parent not found, error */
403 printf ("\n"
404 "Error: parents must be declared before childrens when\n"
405 " creating sampling dependencies - Exiting.\n\n");
406 exit(0);
407 }
408 }
409 }
410 }
411
412 } /* SetParents */
413
414
415 /* End */
416