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