1 /* optdesign.c
2
3 Originally written by Frederic Bois
4 16 August 1997
5
6 Copyright (c) 1997-2017 Free Software Foundation, Inc.
7
8 This file is part of GNU MCSim.
9
10 GNU MCSim is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 3
13 of the License, or (at your option) any later version.
14
15 GNU MCSim is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with GNU MCSim; if not, see <http://www.gnu.org/licenses/>
22 */
23
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "optdsign.h"
29 #include "hungtype.h"
30 #include "lexerr.h"
31 #include "matutil.h"
32 #include "mh.h"
33 #include "simmonte.h"
34 #include "yourcode.h"
35
36 enum {Shannon, Var_Reduction}; /* optimization criterion */
37
38
39 /* ----------------------------------------------------------------------------
40 InitOptArrays
41
42 Count Data statements and initialize some arrays.
43 */
44
InitOptArrays(PANALYSIS panal,int ** piDesign_mask,long * pnDesignPts,double *** pdY,long * pnPreds,long * pnStartDecisionPts,double ** pdVariance,double ** pdIR,long nSims)45 void InitOptArrays (PANALYSIS panal, int **piDesign_mask,
46 long *pnDesignPts, double ***pdY, long *pnPreds,
47 long *pnStartDecisionPts, double **pdVariance,
48 double **pdIR, long nSims)
49 {
50 BOOL bFound;
51 int i, j, k;
52 OUTSPEC *pos;
53
54 /* Count the total number of predictions requested and the data points
55 specified (a prediction+data pair defines a design points */
56 *pnPreds = *pnDesignPts = 0;
57 for (i = 0; i < panal->expGlobal.iExp; i++) {
58 pos = &panal->rgpExps[i]->os;
59 bFound = FALSE;
60 for (j = 0; j < pos->nOutputs; j++) {
61 for (k = 0; k < pos->pcOutputTimes[j]; k++) {
62
63 /* if a Data statement exists that's a design point */
64 if (pos->prgdDataVals) {
65 (*pnDesignPts)++;
66 bFound = TRUE;
67 }
68 (*pnPreds)++;
69 } /* for k */
70 } /* for j */
71 if (bFound)
72 /* Simulation i contained a data statement, decision points start at
73 least in the next Simulation */
74 *pnStartDecisionPts = *pnPreds;
75 } /* for i */
76
77 if (*pnDesignPts == 0) { /* no design points ? */
78 printf("Error: you must provide Data Statements ");
79 printf("for at least one Simulation to define design points - Exiting.\n");
80 exit(0);
81 }
82
83 if (*pnPreds == *pnDesignPts) { /* no pure predictions ? */
84 printf ("Error: you must provide at least one Simulation ");
85 printf ("without Data Statements for utility computations - Exiting.\n");
86 exit(0);
87 }
88
89 /* allocate the piDesign_mask array: one per design point */
90 /* allocate the pdVariance array: one per design point */
91 /* allocate the pdIR array: one per iteration */
92 /* allocate the pdY matrix */
93 if (( !(*piDesign_mask = InitiVector (*pnDesignPts))) ||
94 ( !(*pdVariance = InitdVector (*pnDesignPts))) ||
95 ( !(*pdIR = InitdVector (nSims))) ||
96 ( !(*pdY = InitdMatrix (nSims, *pnPreds))))
97 ReportError (NULL, RE_OUTOFMEM | RE_FATAL, "InitOptArrays", NULL);
98
99 } /* InitOptArrays */
100
101
102 /* ----------------------------------------------------------------------------
103 OpenOptFiles
104
105 Opens the output file.
106 */
107
OpenOptFiles(PANALYSIS panal)108 void OpenOptFiles (PANALYSIS panal)
109 {
110 /* take care of the output file first */
111
112 /* use command line spec if given */
113 if (panal->bCommandLineSpec)
114 panal->gd.szGout = panal->szOutfilename;
115
116 /* use default name if none given */
117 else if (!(panal->gd.szGout))
118 panal->gd.szGout = "simopt.default.out";
119
120 if (!(panal->gd.pfileOut)
121 && !(panal->gd.pfileOut = fopen (panal->gd.szGout, "w")))
122 ReportError (NULL, RE_FATAL | RE_CANNOTOPEN,
123 panal->gd.szGout, "[in OpenOptFiles()]");
124
125 } /* OpenOptFiles */
126
127
128 /* ----------------------------------------------------------------------------
129 WriteOutHeader
130
131 Prints a tabulated header at the top of the output file.
132 */
133
WriteOutHeader(PANALYSIS panal,int criterion)134 void WriteOutHeader (PANALYSIS panal, int criterion)
135 {
136 int i, j, k;
137 OUTSPEC *pos;
138
139 fprintf (panal->gd.pfileOut, "iter\t");
140
141 for (i = 0; i < panal->expGlobal.iExp; i++) {
142 pos = &panal->rgpExps[i]->os;
143 for (j = 0; j < pos->nOutputs; j++) {
144 for (k = 0; k < pos->pcOutputTimes[j]; k++) {
145 /* if a Data statement exists... */
146 if (pos->prgdDataVals)
147 fprintf (panal->gd.pfileOut, "T%g\t", pos->prgdOutputTimes[j][k]);
148 }
149 }
150 }
151
152 fprintf (panal->gd.pfileOut, "Chosen\t");
153
154 if (criterion == Var_Reduction)
155 fprintf (panal->gd.pfileOut, "Variance\tSD\tUtility\n");
156
157 fflush (panal->gd.pfileOut);
158
159 } /* WriteOutHeader */
160
161
162 /* ----------------------------------------------------------------------------
163 SetupLikes
164
165 Scan each Monte Carlo variable to find likelihoods and set
166 their pdParms to data and output arrays. pdVal and dVal are not set.
167 */
168
SetupLikes(PANALYSIS panal,long nPreds,PMCVAR ** pLikes)169 void SetupLikes (PANALYSIS panal, long nPreds, PMCVAR **pLikes)
170 {
171 BOOL bFound, bLikeFound;
172 long i, j, k, m, n;
173 long nPts = 0;
174 OUTSPEC *pos;
175 PMCVAR pMCVar;
176 PMONTECARLO pMC = &panal->mc;
177
178 /* Create an array of pointers to MCVars, one for each design point */
179 if (!(*pLikes = (PMCVAR*) malloc (nPreds * sizeof(PMCVAR))))
180 ReportError (NULL, RE_OUTOFMEM | RE_FATAL, "SetupLikes", NULL);
181
182 /* Scan all design points, find the likelihood associated with each one */
183 for (i = 0; i < panal->expGlobal.iExp; i++) {
184
185 pos = &panal->rgpExps[i]->os;
186
187 for (j = 0; j < pos->nOutputs; j++) {
188
189 for (k = 0; k < pos->pcOutputTimes[j]; k++) {
190
191 /* Allocate space for an MCVar likelihood specification */
192 if (!((*pLikes)[nPts] = (PMCVAR) malloc (sizeof(MCVAR))))
193 ReportError (NULL, RE_OUTOFMEM | RE_FATAL, "SetupLikes", NULL);
194
195 /* If a Data statement exists that's a design point */
196 if (pos->prgdDataVals) {
197
198 /* Find the likelihood statement associated with the current
199 output variable */
200 bLikeFound = FALSE;
201 m = pMC->nSetParms;
202 while (!bLikeFound) {
203 bLikeFound = (pMC->rgpMCVar[m]->hvar == pos->phvar_out[j]);
204 if (!bLikeFound) m++;
205 }
206
207 if (bLikeFound) { /* Set pointers of MCVar */
208
209 pMCVar = pMC->rgpMCVar[m];
210
211 /* You can use parameters defined in the read-in list in
212 Likelihoods. You cannot yet add Distrib statements (that
213 would require more accounting, checking and sampling */
214 /* Fetch pointers to the parents in read-in list */
215 SetParents (pMC, 0);
216
217 /* Set the data and predictions pdParms of pMCVar */
218 for (m = 0; m < 4; m++) {
219
220 if (pMCVar->iParmType[m] == MCVP_PRED) { /* it's an output */
221 /* Set pdParm[m] to an output, first find it */
222 bFound = FALSE;
223 n = 0;
224 while ((n < pos->nOutputs) && (!bFound)) {
225 bFound = (pMCVar->hParm[m] == pos->phvar_out[n]);
226 if (!bFound) n++;
227 }
228 if (bFound) {
229 pMCVar->pdParm[m] = &(pos->prgdOutputVals[n][k]);
230 }
231 else { /* no corresponding Print statement found: error */
232 printf ("Error: missing Print statement for parameter "
233 "number %ld of %s distribution - Exiting.\n\n",
234 j, pMCVar->pszName);
235 exit (0);
236 }
237 } /* end if MCVP_PRED */
238
239 else if (pMCVar->iParmType[m] == MCVP_DATA) { /* it's data */
240 /* Set pdParm[m] to a data array, first find it */
241 bFound = FALSE;
242 n = 0;
243 while ((n < pos->nData) && (!bFound)) {
244 bFound = (pMCVar->hParm[m] == pos->phvar_dat[n]);
245 if (!bFound) n++;
246 }
247 if (bFound) {
248 pMCVar->pdParm[m] = &(pos->prgdDataVals[n][k]);
249 }
250 else { /* no Data found: error */
251 printf ("Error: no Data for %s in Simulation %ld "
252 "- Exiting.\n\n", pMCVar->pszName, i);
253 exit (0);
254 }
255 } /* end if MCVP_DATA */
256 } /* for m */
257 } /* end if bLikeFound */
258 else {
259 /* No likelihood statement found for the current output: error */
260 printf ("Error: missing Likelihood for %s - Exiting.\n\n",
261 pos->pszOutputNames[j]);
262 exit (0);
263 }
264
265 /* Copy the MCVar created */
266 memcpy ((*pLikes)[nPts], pMCVar, sizeof (MCVAR));
267
268 } /* if data */
269
270 else { /* no data: give a null likelihood spec */
271 (*pLikes)[nPts] = NULL;
272 }
273
274 /* Increment likelihood array index */
275 nPts = nPts + 1;
276
277 } /* for k */
278 } /* for j */
279 } /* for i */
280
281 } /* SetupLikes */
282
283
284 /* ----------------------------------------------------------------------------
285 Estimate_y
286
287 Calculates y[] for the given conditions by running the model.
288 y[] is then flattened in the pdY array.
289
290 Note that pdY may not be completely initialized by this routine if it
291 is passed uninitialized.
292 */
293
Estimate_y(PANALYSIS panal,double * pdTheta,double * pdY)294 int Estimate_y (PANALYSIS panal, double *pdTheta, double *pdY)
295 {
296 int cNPred = 0;
297 int i, j, k;
298 OUTSPEC *pos;
299
300 /* Run the PBPK model for each experiment assigned to the subject specified
301 */
302 for (i = 0; i < panal->expGlobal.iExp; i++) {
303 InitModel ();
304
305 /* global modifications */
306 ModifyParms (panal->expGlobal.plistParmMods);
307
308 /* set params to pdTheta values */
309 SetParms (panal->mc.nSetParms, panal->mc.rghvar, pdTheta);
310
311 /* set the Mods for this exp */
312 ModifyParms (panal->rgpExps[i]->plistParmMods);
313
314 if (!DoOneExperiment (panal->rgpExps[i])) {
315 /* Error */
316 printf ("Warning: Can't estimate y with parameters:\n");
317 WriteArray (stdout, panal->mc.nSetParms, pdTheta);
318 fputc('\n', stdout);
319 return 0;
320 } /* if */
321
322 /* link pdY to outputs */
323 pos = &panal->rgpExps[i]->os;
324 for (j = 0; j < pos->nOutputs; j++) {
325 for (k = 0; k < pos->pcOutputTimes[j]; k++) {
326 pdY[cNPred] = pos->prgdOutputVals[j][k];
327 cNPred++;
328 } /* for k */
329 } /* for j */
330
331 } /* for i */
332
333 return 1;
334
335 } /* Estimate_y */
336
337
338 /* ----------------------------------------------------------------------------
339 ReadAndSimulate
340
341 Initialize arrays and reads a parameter sample, obtained for example
342 from a previous MCMC sample. Run the structural model, simulate data
343 and output the loglikelihood of each design point (Outputs having
344 associated Data statements) in pdY. For non-design points of output
345 pdY contains just the output value (not its log-likelihood).
346
347 */
348
ReadAndSimulate(PANALYSIS panal,long nSetParms,double ** pdY,long nPreds,PMCVAR * pLikes,long nSims)349 void ReadAndSimulate (PANALYSIS panal, long nSetParms,
350 double **pdY, long nPreds, PMCVAR *pLikes, long nSims)
351 {
352 register char c;
353 long lDummy, iter = 0;
354 long j;
355 PDOUBLE pdTheta = NULL;
356 PDOUBLE pdTheta_0 = NULL;
357 PDOUBLE pdData = NULL;
358 PDOUBLE pdData_old = NULL;
359 FILE *pfileRestart = panal->gd.pfileRestart;
360
361 /* Temporary space allocation for model parameters and simulated data */
362 if ( !(pdTheta = InitdVector (nSetParms)) ||
363 !(pdTheta_0 = InitdVector (nSetParms)) ||
364 !(pdData_old = InitdVector (nPreds)) ||
365 !(pdData = InitdVector (nPreds)))
366 ReportError (NULL, RE_OUTOFMEM | RE_FATAL, "ReadAndSimulate", NULL);
367
368 /* open the restart file */
369 if (!(pfileRestart)
370 && !(pfileRestart = fopen (panal->gd.szGrestart, "r")))
371 ReportError (NULL, RE_FATAL | RE_CANNOTOPEN,
372 panal->gd.szGrestart, "[in ReadAndSimulate()]");
373
374 /* Skip the first line. This allows a MC output file to be used
375 directly as a restart file. */
376 do { c = getc(pfileRestart); } while (c != '\n');
377
378 /* Keep reading lines as long as iter < nSims and we have not reached
379 the end of the file.
380 Also keep incrementing the global iteration counter, iter: */
381 while ((iter < nSims) &&
382 ( !(feof(pfileRestart) ||
383 (fscanf(pfileRestart, "%ld", &lDummy) == EOF)))) {
384
385 /* Read model parameters in pdTheta */
386 for (j = 0; j < nSetParms; j++) {
387 if (!fscanf (pfileRestart, "%lg", &(pdTheta[j])))
388 ReportError (NULL, RE_READERROR | RE_FATAL, panal->gd.szGrestart, NULL);
389 else
390 panal->mc.rgpMCVar[j]->dVal = pdTheta[j];
391 }
392
393 /* Throw away remainder of line */
394 do { c = getc(pfileRestart); } while (c != '\n');
395
396 /* For all experiments, compute the predictions for the parameter vector */
397 Estimate_y (panal, pdTheta, pdY[iter]);
398
399 if (iter == 0) { /* first simulation, just make predictions */
400 for (j = 0; j < nSetParms; j++) {
401 pdTheta_0[j] = pdTheta[j]; /* save parameter vector for reuse at end */
402 }
403 for (j = 0; j < nPreds; j++) {
404 if (pLikes[j] != NULL) {
405 CalculateOneMCParm (pLikes[j]);
406 pdData_old[j] = pLikes[j]->dVal;
407 }
408 }
409 }
410 else { /* other iterations */
411 /* Simulate data */
412 for (j = 0; j < nPreds; j++) {
413 if (pLikes[j] != NULL) {
414 CalculateOneMCParm (pLikes[j]);
415 pdData[j] = pLikes[j]->dVal;
416 }
417 }
418
419 /* Compute the data likelihood with the previous iteration data vector */
420 for (j = 0; j < nPreds; j++)
421 if (pLikes[j] != NULL) {
422 pLikes[j]->dVal = pdData_old[j];
423 pdY[iter][j] = LnDensity (pLikes[j], panal);
424
425 /* Update old data vector */
426 pdData_old[j] = pdData[j];
427 }
428
429 if (iter == nSims - 1) { /* last iteration: process the first one also */
430 /* Recompute the predictions to be up to date for all outputs because
431 likelihood parameters may point to panal->os internal variables */
432 Estimate_y (panal, pdTheta_0, pdY[0]);
433 for (j = 0; j < nPreds; j++)
434 if (pLikes[j] != NULL) {
435 pLikes[j]->dVal = pdData_old[j];
436 pdY[0][j] = LnDensity (pLikes[j], panal);
437 }
438 }
439 } /* end else iter */
440
441 /* Increment iter */
442 iter++;
443
444 } /* end while */
445
446 if (iter < nSims) {
447 printf ("\nError: The number of lines in file %s is less than\n",
448 panal->gd.szGrestart);
449 printf (" the number of lines to read (%ld) - Exiting\n", nSims);
450 exit (0);
451 }
452
453 fclose (pfileRestart);
454
455 } /* ReadAndSimulate */
456
457
458 /* ----------------------------------------------------------------------------
459 Do_Importance_Ratios
460
461 Compute the expected likelihood of nDesignPts and forms the
462 importance ratios by scaling them to their sum.
463 The prediction array MUST contain the log-likelihood of individual data
464 points.
465
466 Uses piDesign_mask to select the design points to consider.
467 */
468
Do_Importance_Ratios(double ** pdY,PMCVAR * pLikes,long nSims,long nPreds,long nDesignPts,int * piDesign_mask,int nDesignPt_tried,double * pdIR)469 void Do_Importance_Ratios (double **pdY, PMCVAR *pLikes, long nSims,
470 long nPreds, long nDesignPts, int *piDesign_mask,
471 int nDesignPt_tried, double *pdIR)
472 {
473 long i, j, k;
474 double dSumL = 0;
475 BOOL bOn;
476
477 for (k = 0; k < nSims; k++) {
478 pdIR[k] = 0;
479 j = 0;
480 for (i = 0; i < nPreds; i++) {
481 if (pLikes[i] != NULL) {
482 if (j == nDesignPt_tried) /* invert the current mask */
483 bOn = ! piDesign_mask[j];
484 else /* straigth mask */
485 bOn = piDesign_mask[j];
486
487 /* Form the log-likelihood for all design experiments */
488 if (bOn)
489 pdIR[k] = pdIR[k] + pdY[k][i];
490
491 j++;
492 } /* if pLikes */
493 } /* for i */
494
495 pdIR[k] = exp(pdIR[k]);
496 dSumL = dSumL + pdIR[k];
497
498 } /* for k */
499
500 for (k = 0; k < nSims; k++)
501 pdIR[k] = pdIR[k] / dSumL;
502
503 } /* Do_Importance_Ratios */
504
505
506 /* ----------------------------------------------------------------------------
507 DoVariance
508
509 Compute the total variance (after log transformation) of elements of a
510 matrix, considering importance ratios.
511 Only part of the matrix (from istart to ifinish) is used.
512 */
513
DoVariance(long nDim,double * pdIR,double ** pdX,long istart,long ifinish)514 double DoVariance (long nDim, double *pdIR, double **pdX,
515 long istart, long ifinish)
516 {
517 long i, j;
518 register double ave, ss, dTmp;
519
520 ss = 0;
521
522 /* for all predictions (X between istart and ifinish) */
523 for (i = istart; i < ifinish; i++) {
524 ave = 0;
525 /* Compute the average pdX */
526 for (j = 0; j < nDim; j++) {
527 ave = ave + pdIR[j] * log(pdX[j][i]);
528 }
529
530 /* Compute the SS over pdX */
531 for (j = 0; j < nDim; j++) {
532 dTmp = log(pdX[j][i]) - ave;
533 ss = ss + pdIR[j] * dTmp * dTmp;
534 }
535 }
536
537 return (ss / (double) (ifinish - istart));
538
539 } /* DoVariance */
540
541
542 /* ----------------------------------------------------------------------------
543 Compute_utility
544
545 Utilities can be computed here: totally arbitrary and unused for now
546 */
547
Compute_utility(long nDesignPts,int * piDesign_mask,double * dUtility)548 void Compute_utility (long nDesignPts, int *piDesign_mask, double *dUtility)
549 {
550 int nPts = 0;
551 int i;
552
553 for (i = 0; i < nDesignPts; i++)
554 if (piDesign_mask[i]) nPts++;
555
556 /* Let say that cost is 2 monetary units per design point */
557 *dUtility = -2 * nPts;
558
559 } /* Compute_utility */
560
561
562 /* ----------------------------------------------------------------------------
563 WriteOptimOut
564
565 writes to the output file, print only the significant portions.
566 */
567
WriteOptimOut(PANALYSIS panal,long iter,long nDesignPts,int criterion,double * pdVariance,int * piDesign_mask,long iCrit,double dCrit,double dUtility)568 void WriteOptimOut (PANALYSIS panal, long iter, long nDesignPts,
569 int criterion, double *pdVariance, int *piDesign_mask,
570 long iCrit, double dCrit, double dUtility)
571 {
572 long i;
573
574 fprintf (panal->gd.pfileOut, "%ld\t", iter);
575
576 if (iCrit < nDesignPts) { /* if iCrit is usefully defined */
577 for (i = 0; i < nDesignPts; i++) {
578 if ((&panal->mc)->style == forward) {
579 if ((i == iCrit) || !(piDesign_mask[i]))
580 fprintf (panal->gd.pfileOut, "%g\t", pdVariance[i]);
581 else
582 fprintf (panal->gd.pfileOut, "0\t");
583 }
584 else { /* backward style, the mask needs to be inverted */
585 if (!(piDesign_mask[i]))
586 fprintf (panal->gd.pfileOut, "0\t");
587 else
588 fprintf (panal->gd.pfileOut, "%g\t", pdVariance[i]);
589 }
590 } /* end for */
591
592 fprintf (panal->gd.pfileOut, "%ld\t", iCrit+1);
593 }
594 else
595 for (i = 0; i <= nDesignPts; i++)
596 fprintf (panal->gd.pfileOut, "0\t");
597
598 if (criterion == Var_Reduction)
599 fprintf (panal->gd.pfileOut, "%g\t%g\t%g\n", dCrit, sqrt(dCrit), dUtility);
600
601 fflush (panal->gd.pfileOut);
602
603 } /* WriteOptimOut */
604
605
606 /* ----------------------------------------------------------------------------
607 Importance_Resample
608
609 Does just that, updating pIndex1, picking from pIndex0, pdL is destroyed.
610 */
611
Importance_Resample(long nSims,long * pIndex0,long * pIndex1,long * plDrawn,double * pdL,double dSumL)612 void Importance_Resample (long nSims, long *pIndex0, long *pIndex1,
613 long *plDrawn, double *pdL, double dSumL)
614 {
615 long i, j;
616
617 /* do the weights */
618 for (i = 0; i < nSims; i++)
619 pdL[i] = pdL[i] / dSumL;
620
621 j = 0;
622 do {
623 /* randomly pick a vector among the nSims available. No risk of
624 overflow because Randoms() is between 0 and 1 */
625 i = (long) floor (Randoms() * nSims);
626
627 if (Randoms() < pdL[i]) { /* accept */
628 pIndex1[j] = pIndex0[i];
629 j++;
630 plDrawn[pIndex0[i]]++;
631 }
632 }
633 while (j < nSims);
634
635 } /* Importance_Resample */
636
637
638 /* ----------------------------------------------------------------------------
639 CloseOptFiles
640
641 Closes output files associated with the design optimizer.
642 The restart file has already been closed by the ReadAndSimulate
643
644 */
645
CloseOptFiles(PANALYSIS panal)646 void CloseOptFiles (PANALYSIS panal)
647 {
648 if (panal->gd.pfileOut) {
649 fclose (panal->gd.pfileOut);
650 printf ("\nWrote results to \"%s\"\n", panal->gd.szGout);
651 }
652
653 } /* CloseOptFiles */
654
655
656 /* ----------------------------------------------------------------------------
657 DoOptimalDesign
658
659 Core routine of the experimental design optimizer
660 */
661
DoOptimalDesign(PANALYSIS panal)662 void DoOptimalDesign (PANALYSIS panal)
663 {
664 PGIBBSDATA pgd = &panal->gd;
665 PMONTECARLO pmc = &panal->mc;
666
667 long i, j;
668 long iBest = 0;
669 long dim;
670 long nDesignPts; /* # of data points in a data set */
671 long nPreds; /* # of predicted values */
672 long nSims = pmc->nRuns; /* # of model parametrizations tested */
673 int *piDesign_mask; /* current mask for likelihood computation */
674 long nDesignPt_tried; /* index of the currently tried time point */
675 long nStartDecisionPts; /* index to the start of decision points */
676 int criterion; /* either Shannon's or variance reduction */
677 double dBest = 0; /* best criterion */
678 double dUtility = 0; /* total utility of a design */
679 double *pdIR; /* array of importance ratios (dim: nSims) */
680 double *pdVariance; /* pred. variances. associated to a design pt */
681 double **pdY; /* predictions, then likelihoods */
682 PMCVAR *pLikes; /* array of likelihood specifications */
683
684 /* criterion can be Var_Reduction or Shannon */
685 criterion = Var_Reduction;
686 if (criterion != Var_Reduction) {
687 printf ("Oooops, Shannon not implemented - exiting\n");
688 exit (0);
689 }
690
691 /* announce the work to be done */
692 printf ("\nDoing analysis - Optimal Design %s %s - %d experiment%c\n",
693 (pmc->style == forward ? "forward" : "backward"),
694 (criterion == Var_Reduction ? "variance reduction" : "Shannon"),
695 panal->expGlobal.iExp, (panal->expGlobal.iExp > 1 ? 's' : ' '));
696
697 /* open restart and output files */
698 OpenOptFiles (panal);
699
700 /* Initialize the design-points and predictions arrays */
701 InitOptArrays (panal, &piDesign_mask, &nDesignPts, &pdY, &nPreds,
702 &nStartDecisionPts, &pdVariance, &pdIR, nSims);
703
704 /* Associate predictions to MCVars likelihood records */
705 SetupLikes (panal, nPreds, &pLikes);
706
707 /* Read in the parameter samples and simulate predictions */
708 if (!(pgd->szGrestart)) {
709 /* error: we must have a starting prior sample */
710 printf ("Error: there must be a parameter sample file - Exiting\n");
711 exit (0);
712 }
713 else {
714 /* read the starting values in the order they are printed and
715 close the file when finished */
716 ReadAndSimulate (panal, pmc->nSetParms, pdY, nPreds, pLikes, nSims);
717 }
718
719 /* Write the header line of the output file */
720 WriteOutHeader (panal, criterion);
721
722 /* Turn experimental points on (backward trials) or off (forward trials) */
723 for (i = 0; i < nDesignPts; i++)
724 piDesign_mask[i] = !(pmc->style == forward);
725
726 /* Start the computation */
727 if (criterion == Var_Reduction) {
728
729 if (pmc->style == backward) { /* all points included */
730
731 /* Set nDesignPt_tried at a value beyond the array bounds so that it is
732 not found and does not interfere in the next call to Likelihood */
733 nDesignPt_tried = nDesignPts + 1;
734
735 /* Compute the importance ratios of each parameter set */
736 Do_Importance_Ratios (pdY, pLikes, nSims, nPreds, nDesignPts,
737 piDesign_mask, nDesignPt_tried, pdIR);
738
739 /* Compute the total variance of the pure predictions (decision
740 points) */
741 dBest = DoVariance (nSims, pdIR, pdY, nStartDecisionPts, nPreds);
742 }
743 else { /* forward style is simple */
744 for (j = 0; j < nSims; j++)
745 pdIR[j] = 1 / (double) nSims;
746
747 dBest = DoVariance (nSims, pdIR, pdY, nStartDecisionPts, nPreds);
748 }
749 }
750
751 iBest = nDesignPts + 1; /* out of bounds, undefined */
752
753 /* Compute_utility (nDesignPts, piDesign_mask, &dUtility); */
754
755 /* output the first line ... */
756 WriteOptimOut (panal, 0, nDesignPts, criterion, pdVariance, piDesign_mask,
757 iBest, dBest, dUtility);
758
759 /* Start the loop over designs points, only some of the previously
760 computed points will be used */
761 dim = ((pmc->style == backward) ? nDesignPts - 1 : nDesignPts);
762 for (i = 0; i < dim; i++) {
763
764 /* Reset the criterion for "best" */
765 if (criterion == Var_Reduction)
766 dBest = DBL_MAX;
767
768 for (j = 0; j < nDesignPts; j++) {
769
770 /* Try this point, if it is not already accepted or deleted.
771 (style == backward) is 1 in case of backward style and 0 in
772 case of forward style. So if we go backward we skip the point
773 if it is already "off" */
774 if (piDesign_mask[j] == (pmc->style == backward)) {
775
776 nDesignPt_tried = j; /* try add or remove point j */
777
778 pdVariance[j] = 0; /* reset */
779
780 /* Check whether this point is the best of the j tried so far */
781 if (criterion == Var_Reduction) {
782
783 /* Do an importance reweighting to be able to get the variance
784 reductions */
785 Do_Importance_Ratios (pdY, pLikes, nSims, nPreds, nDesignPts,
786 piDesign_mask, nDesignPt_tried, pdIR);
787
788 /* Compute the total variance of the decision points */
789 pdVariance[j] = DoVariance (nSims, pdIR, pdY, nStartDecisionPts,
790 nPreds);
791
792 } /* if */
793
794 /* If forward we want to keep the point giving the best reduction,
795 i.e. the lowest variance; if backward we want to remove the point
796 giving the lowest variance augmentation, which is also the lowest
797 variance */
798 if (dBest > pdVariance[j]) {
799 dBest = pdVariance[j];
800 iBest = j;
801 }
802
803 } /* if piDesign_mask */
804
805 } /* for j design point */
806
807 /* set the best point, by inverting it definitely */
808 piDesign_mask[iBest] = !piDesign_mask[iBest];
809
810 /* Compute_utility (nDesignPts, piDesign_mask, &dUtility); */
811
812 /* output ... */
813 WriteOptimOut (panal, i+1, nDesignPts, criterion, pdVariance,
814 piDesign_mask, iBest, dBest, dUtility);
815
816 printf ("%ld points design done\n", i+1);
817
818 } /* for i */
819
820 /* if style is backward we would still like to know what a zero-point design
821 would do */
822 if (pmc->style == backward) {
823
824 /* Importance ratios are reinitialized with the natural weights */
825 for (j = 0; j < nSims; j++) pdIR[j] = 1 / (double) nSims;
826
827 if (criterion == Var_Reduction) {
828 dBest = DoVariance (nSims, pdIR, pdY, nStartDecisionPts, nPreds);
829 j = 0;
830 while (piDesign_mask[j] == 0)
831 j++;
832 iBest = j;
833 }
834
835 /* Output, with null utility */
836 WriteOptimOut (panal, nDesignPts, nDesignPts, criterion, pdVariance,
837 piDesign_mask, iBest, dBest, 0);
838
839 printf ("%ld points design done\n", nDesignPts);
840 }
841
842 free (piDesign_mask);
843
844 CloseOptFiles (panal);
845
846 } /* DoOptimalDesign */
847
848