EMMA Coverage Report (generated Wed Sep 07 21:54:19 EEST 2005)
[all classes][PIANOS.io]

COVERAGE SUMMARY FOR SOURCE FILE [ComputationalModelParser.java]

nameclass, %method, %block, %line, %
ComputationalModelParser.java100% (1/1)95%  (21/22)78%  (3793/4871)90%  (896,6/994)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ComputationalModelParser100% (1/1)95%  (21/22)78%  (3793/4871)90%  (896,6/994)
ComputationalModelParser (): void 0%   (0/1)0%   (0/3)0%   (0/2)
readMissing (File, boolean, int, int, int, int, boolean [][], String, Scanner... 100% (1/1)60%  (143/237)84%  (32/38)
readInitialValues (File, HashMap): void 100% (1/1)64%  (534/838)86%  (132/153)
checkSpats (HashMap, File): void 100% (1/1)65%  (34/52)90%  (9/10)
readProposal (File, HashMap, DistributionFactory): void 100% (1/1)68%  (198/293)87%  (59/68)
readUpdate (File, HashMap, String): Object [] 100% (1/1)69%  (105/153)92%  (34/37)
readUpdateValues (boolean, File, Scanner, HashMap): int 100% (1/1)70%  (119/169)88%  (38/43)
readOutput (File, HashMap): String [] 100% (1/1)70%  (167/237)91%  (41/45)
readEntity (File, LinkedList, HashMap, HashMap, String, Scanner, Distribution... 100% (1/1)73%  (334/460)88%  (78,6/89)
checkVariablesAreOk (ArrayList): void 100% (1/1)75%  (70/93)77%  (10/13)
readData (Entity): void 100% (1/1)77%  (440/568)85%  (88/103)
countNeighbours (LinkedList): int 100% (1/1)81%  (112/138)92%  (36/39)
testNoInitialValues (String, String, String, String, String, DistributionFact... 100% (1/1)86%  (148/173)88%  (36/41)
readModel (String, String, String, String, String, String, DistributionFactor... 100% (1/1)88%  (215/245)91%  (58/64)
readModelFile (File, LinkedList, LinkedList, HashMap, HashMap, DistributionFa... 100% (1/1)88%  (86/98)95%  (21/22)
readUnifiedFormatFile (File, String, String, String): int [] 100% (1/1)88%  (121/137)97%  (37/38)
modelTestOnly (String, String, DistributionFactory): ComputationalModel 100% (1/1)90%  (92/102)92%  (23/25)
parseVariable (File, boolean, String, HashMap, DistributionFactory): Variable 100% (1/1)100% (818/818)100% (150/150)
readEntityData (LinkedList): void 100% (1/1)100% (19/19)100% (6/6)
readMissing (File, boolean, int, int, boolean [][], String, Scanner): void 100% (1/1)100% (11/11)100% (2/2)
readSimulation (File): int [] 100% (1/1)100% (6/6)100% (1/1)
readglobal (File, boolean, String, HashMap, LinkedList, DistributionFactory):... 100% (1/1)100% (21/21)100% (5/5)

1package PIANOS.io;
2import PIANOS.datastructures.*;
3import PIANOS.exceptions.*;
4 
5// data structures
6import java.util.HashMap;
7import java.util.LinkedList;
8import java.util.ArrayList;
9 
10// general reading
11import java.util.Scanner;
12 
13// reading the data files
14import java.util.StringTokenizer;
15 
16// parsing the equations correctly
17import java.util.regex.Pattern;
18import java.util.regex.Matcher;
19 
20// File, IOException, etc...
21import java.io.*;
22 
23/**
24 * The PIANOS parser
25 * Reads input files with readModel and returns the corresponding model.
26 * @author Eemil Lagerspetz
27 */
28public class ComputationalModelParser{
29    
30    private ComputationalModelParser(){
31    }
32    
33    private static int line;
34    /** Public for testing purposes, do not modify.
35     */
36    public static ArrayList<Variable> toBeChecked;
37    /** Public for testing purposes, do not modify.
38     */
39    public static HashMap<Variable, String> spatAffectedMap;
40    private static HashMap<String, Entity> belongMap;
41    
42    public static ComputationalModel modelTestOnly(String modelFileName,
43            String proposalFileName,
44            DistributionFactory factory)
45            throws IOException, SyntaxException, MissingDistributionException{
46        
47        // we are supposed to create a ComputationalModel, so let's do just that.
48        // First initialize the files...
49        if (modelFileName == null)
50            throw new IOException("Can't read a file with null name as modelFileName");
51        if (proposalFileName == null)
52            throw new IOException("Can't read a file with null name as proposalFileName");
53        
54        File modelFile = new File(modelFileName);
55        File proposalFile = new File(proposalFileName);
56        
57        // build the components...
58        int iterations = 0;
59        int burnIn = 0;
60        int thinning = 0;
61        int neighbours = 0;
62        String updateStrategy = "";
63        
64        LinkedList<Variable> variableList = new LinkedList<Variable>();
65        LinkedList<Entity> entityList = new LinkedList<Entity>();
66        HashMap<String, Entity> entityMapper = new HashMap<String, Entity>();
67        HashMap<String, Variable> variableMapper = new HashMap<String, Variable>();
68        
69        // and start setting them:
70        toBeChecked = new ArrayList<Variable>();
71        spatAffectedMap = new HashMap<Variable, String>();
72        
73        readModelFile(modelFile, variableList, entityList, entityMapper, variableMapper, factory);
74        
75        // now we might have stuff in toBeChecked and spatAffectedMap.
76        
77        /* These operations still need to be done for stuff in them.
78           toAdd.addDependence(dep);
79           dep.addAffected(toAdd);
80           variables.add(dep);
81         */
82        
83        checkSpats(variableMapper, modelFile);
84        
85        // now they should be alright.
86        
87        readProposal(proposalFile, variableMapper, factory);
88        
89        readEntityData(entityList);
90        
91        neighbours = countNeighbours(entityList);
92        
93        checkVariablesAreOk(new ArrayList<Variable>(variableMapper.values()));
94        
95        ComputationalModel model = new ComputationalModel(iterations, burnIn, thinning, neighbours,
96                updateStrategy, variableList, entityList, entityMapper, variableMapper, modelFileName,
97                null, null, null);
98        return model;
99    }
100    
101    public static ComputationalModel testNoInitialValues(String modelFileName,
102            String simulationFileName,
103            String proposalFileName,
104            String updateFileName,
105            String toOutputFileName, DistributionFactory factory)
106            throws IOException, SyntaxException, MissingDistributionException{
107        if (modelFileName == null)
108            throw new IOException("Can't read a file with null name as modelFileName");
109        //        if (initialValueFileName == null)
110        //            throw new IOException("Can't read a file with null name as initialValueFileName");
111        if (simulationFileName == null)
112            throw new IOException("Can't read a file with null name as simulationFileName");
113        if (proposalFileName == null)
114            throw new IOException("Can't read a file with null name as proposalFileName");
115        if (updateFileName == null)
116            throw new IOException("Can't read a file with null name as updateFileName");
117        if (toOutputFileName == null)
118            throw new IOException("Can't read a file with null name as toOutputFileName");
119        
120        File modelFile = new File(modelFileName);
121        //        File initialValuesFile = new File(initialValueFileName);
122        File simulationFile = new File(simulationFileName);
123        File proposalFile = new File(proposalFileName);
124        File updateFile = new File(updateFileName);
125        File toOutputFile = new File(toOutputFileName);
126        
127        // build the components...
128        int iterations = 0;
129        int burnIn = 0;
130        int thinning = 0;
131        int neighbours = 0;
132        String updateStrategy = "";
133        
134        LinkedList<Variable> variableList = new LinkedList<Variable>();
135        LinkedList<Entity> entityList = new LinkedList<Entity>();
136        HashMap<String, Entity> entityMapper = new HashMap<String, Entity>();
137        HashMap<String, Variable> variableMapper = new HashMap<String, Variable>();
138        
139        // and start setting them:
140        toBeChecked = new ArrayList<Variable>();
141        spatAffectedMap = new HashMap<Variable, String>();
142        
143        readModelFile(modelFile, variableList, entityList, entityMapper, variableMapper, factory);
144        
145        // now we might have stuff in toBeChecked and spatAffectedMap.
146        
147        /* These operations still need to be done for stuff in them.
148           toAdd.addDependence(dep);
149           dep.addAffected(toAdd);
150           variables.add(dep);
151         */
152        
153        checkSpats(variableMapper, modelFile);
154        
155        // now they should be alright.
156        
157        int[] temp = readSimulation(simulationFile);
158        burnIn = temp[0];
159        thinning = temp[1];
160        
161        Object[] updateTemp = readUpdate(updateFile, variableMapper , updateStrategy);
162        updateStrategy = (String)updateTemp[0];
163        iterations = (Integer)updateTemp[1];
164        
165        String[] opFiles = readOutput(toOutputFile, variableMapper);
166        
167        readProposal(proposalFile, variableMapper, factory);
168        
169        readEntityData(entityList);
170        
171        neighbours = countNeighbours(entityList);
172        //        readInitialValues(initialValuesFile, variableMapper);
173        
174        checkVariablesAreOk(new ArrayList<Variable>(variableMapper.values()));
175        
176        ComputationalModel model = new ComputationalModel(iterations, burnIn, thinning, neighbours,
177                updateStrategy, variableList, entityList, entityMapper, variableMapper, modelFileName,
178                null, opFiles[0], opFiles[1]);
179        return model;
180    }
181    
182    
183    /**
184     * The main interface for the Parser. All filenames are valid with a relative path.
185     * @param modelFileName the name of the model file
186     * @param initialValueFileName the name of the initial
187     * values file
188     * @param simulationFileName the name of the model file
189     * @param proposalFileName the name of the proposal distributions
190     * file
191     * @param updateFileName the name of the variables update strategy
192     * file
193     * @param toOutputFileName the name of the to_output file
194     * @param factory the DistributionFactory with the user distributions used
195     @return the complete model data structure constructed from the files given.
196     */
197    
198    public static ComputationalModel readModel(String modelFileName,
199            String initialValueFileName,
200            String simulationFileName,
201            String proposalFileName,
202            String updateFileName,
203            String toOutputFileName, DistributionFactory factory)
204            throws IOException, SyntaxException, MissingDistributionException{
205        
206        // we are supposed to create a ComputationalModel, so let's do just that.
207        // First initialize the files...
208        if (modelFileName == null)
209            throw new IOException("Can't read a file with null name as modelFileName");
210        if (initialValueFileName == null)
211            throw new IOException("Can't read a file with null name as initialValueFileName");
212        if (simulationFileName == null)
213            throw new IOException("Can't read a file with null name as simulationFileName");
214        if (proposalFileName == null)
215            throw new IOException("Can't read a file with null name as proposalFileName");
216        if (updateFileName == null)
217            throw new IOException("Can't read a file with null name as updateFileName");
218        if (toOutputFileName == null)
219            throw new IOException("Can't read a file with null name as toOutputFileName");
220        
221        File modelFile = new File(modelFileName);
222        File initialValuesFile = new File(initialValueFileName);
223        File simulationFile = new File(simulationFileName);
224        File proposalFile = new File(proposalFileName);
225        File updateFile = new File(updateFileName);
226        File toOutputFile = new File(toOutputFileName);
227        
228        // build the components...
229        int iterations = 0;
230        int burnIn = 0;
231        int thinning = 0;
232        int neighbours = 0;
233        String updateStrategy = "";
234        
235        LinkedList<Variable> variableList = new LinkedList<Variable>();
236        LinkedList<Entity> entityList = new LinkedList<Entity>();
237        HashMap<String, Entity> entityMapper = new HashMap<String, Entity>();
238        HashMap<String, Variable> variableMapper = new HashMap<String, Variable>();
239        
240        // and start setting them:
241        toBeChecked = new ArrayList<Variable>();
242        spatAffectedMap = new HashMap<Variable, String>();
243        
244        
245        System.out.print("Reading the model file...");
246        readModelFile(modelFile, variableList, entityList, entityMapper, variableMapper, factory);
247        System.out.println("\t\t\t\t\t[OK]");
248        // now we might have stuff in toBeChecked and spatAffectedMap.
249        
250        /* These operations still need to be done for stuff in them.
251           toAdd.addDependence(dep);
252           dep.addAffected(toAdd);
253           variables.add(dep);
254         */
255        
256        checkSpats(variableMapper, modelFile);
257        
258        
259        // now they should be alright.
260        
261        System.out.print("Reading simulation parameters...");
262        int[] temp = readSimulation(simulationFile);
263        burnIn = temp[0];
264        thinning = temp[1];
265        
266        System.out.println("\t\t\t\t[OK]");
267        
268        System.out.print("Reading update file...");
269        Object[] updateTemp = readUpdate(updateFile, variableMapper , updateStrategy);
270        updateStrategy = (String)updateTemp[0];
271        iterations = (Integer)updateTemp[1];
272        System.out.println("\t\t\t\t\t\t[OK]");
273        
274        System.out.print("Getting output variable names...");        
275        String[] opFiles = readOutput(toOutputFile, variableMapper);
276        
277        System.out.println("\t\t\t\t[OK]");
278        
279        
280        System.out.print("Validating proposal distributions...");
281        readProposal(proposalFile, variableMapper, factory);
282        System.out.println("\t\t\t\t[OK]");
283        
284        
285        System.out.print("Validating data...");
286        readEntityData(entityList);
287        System.out.println("\t\t\t\t\t\t[OK]");
288        
289        System.out.print("Finding maximum number of neighbours...");
290        neighbours = countNeighbours(entityList);
291        System.out.println("\t\t\t\t[OK]");
292        
293        System.out.print("Checking initial values...");
294        readInitialValues(initialValuesFile, variableMapper);
295        System.out.println("\t\t\t\t\t[OK]");
296        
297        System.out.print("Model check...");
298        checkVariablesAreOk(new ArrayList<Variable>(variableMapper.values()));
299        System.out.println("\t\t\t\t\t\t\t[OK]");
300        
301        ComputationalModel model = new ComputationalModel(iterations, burnIn, thinning, neighbours,
302                updateStrategy, variableList, entityList, entityMapper, variableMapper, modelFileName,
303                initialValueFileName, opFiles[0], opFiles[1]);
304        
305        System.out.println("Model built.");
306        return model;
307    }
308    
309    private static void checkSpats(HashMap <String, Variable> variableMapper, File modelFile)
310    throws SyntaxException{
311        for (Variable aff : toBeChecked){
312            String varname = spatAffectedMap.get(aff);
313            Variable var = variableMapper.get(varname);
314            if (aff == null)
315                throw new SyntaxException("In "+ modelFile + ": Variable "+ varname +
316                        " is used in a COUNT or SUM statement but never defined");
317            aff.addDependence(var);
318            var.addAffected(aff);
319            // It's good that we defined that SUM and COUNT must appear alone.
320            // otherwise this would have been VERY troublesome.
321            aff.getEquation().setParameters(var);
322        }
323    }
324    
325    /** Reads the model file and puts the information into the maps and lists provided.
326     *
327     */
328    
329    private static void readModelFile(File file, LinkedList<Variable> variableList,
330            LinkedList<Entity> entityList, HashMap<String, Entity> entityMapper,
331            HashMap<String, Variable> variableMapper, DistributionFactory fact)
332            throws IOException, SyntaxException, MissingDistributionException{
333        // reads the model, creates data structures from it, sets the variables' sizes correctly
334        // with help from readData(which creates the missing binary matrix and the modified data
335        // file as a side-product)
336        
337        
338        Scanner reader = new Scanner(file);
339        String temp = null;
340        line = 0;
341        while (reader.hasNextLine()){
342            temp = reader.nextLine();
343            line++;
344            temp = temp.trim();
345            
346            if (temp.length() == 0 || temp.charAt(0) == '#')
347                continue;
348            
349            // now we have a non-comment non-zero line.
350            
351            // it can either be a global variable starting with
352            // REAL or INTEGER,
353            // or it can be an ENTITY definition line starting with ENTITY.
354            
355            if (temp.startsWith("REAL")){
356                temp = temp.substring(4).trim();
357                readglobal(file, false, temp, variableMapper, variableList, fact);
358            } else if (temp.startsWith("INTEGER")){
359                temp = temp.substring(7).trim();
360                readglobal(file, true, temp, variableMapper, variableList, fact);
361            } else if (temp.startsWith("ENTITY")){
362                temp = temp.substring(6).trim();
363                readEntity(file, entityList, entityMapper, variableMapper, temp, reader, fact);
364            } else
365                throw new SyntaxException("No entity or variable on line " + line);
366            
367        }
368        reader.close();
369    }
370    
371    /** Reads a global variable's information from the line provided and saves it to the variablelist and mapper.
372     *
373     */
374    
375    private static void readglobal(File file, boolean isInteger, String toParse,
376            HashMap<String, Variable> variableMapper, LinkedList<Variable> variableList,
377            DistributionFactory fact) throws SyntaxException,
378            MissingDistributionException {
379        Variable toAdd = parseVariable(file, isInteger, toParse, variableMapper, fact);
380        toAdd.setEntity(null); // global
381        variableMapper.put(toAdd.getName(), toAdd);
382        variableList.add(toAdd); // global variables list
383    }
384    
385    /** Reads a variable definition line and returns a representation of the variable, public for testing purposes. Do not call directly.
386     *
387     */
388    
389    public static Variable parseVariable(File file, boolean isInteger, String toParse,
390            HashMap<String, Variable> variableMapper, DistributionFactory fact) throws
391            SyntaxException, MissingDistributionException{
392        Variable toAdd = new Variable();
393        
394        toAdd.setType(isInteger);
395        toParse = toParse.replaceAll("\\p{Space}+", "");
396        /*
397         *Now we have either
398         *nam4e~dist(par,par2,..,par83)
399         *or
400         *nam4e=expression
401         *or
402         *nam4e(index)
403         *or
404         *nam4e(index)~dist(par,...)
405         *or
406         *nam4e(index)=expr
407         */
408        
409        int parenIndex = toParse.indexOf('(');
410        int eqIndex = toParse.indexOf('=');
411        int tildeIndex = toParse.indexOf('~');
412        if (parenIndex == -1)
413            parenIndex = toParse.length();
414        if (eqIndex == -1)
415            eqIndex = toParse.length();
416        if (tildeIndex == -1)
417            tildeIndex = toParse.length();
418        
419        String name = toParse.substring(0, Math.min(parenIndex,
420                Math.min(eqIndex, tildeIndex)));
421        
422        
423        Pattern p = Pattern.compile("[a-z][a-z0-9]*");
424        Matcher m = p.matcher(name);
425        if (!m.matches())
426            throw new SyntaxException("In "+ file + ": Invalid variable name " +
427                    "on line " + line);
428        
429        toAdd.setName(name);
430        
431        toParse = toParse.substring(name.length()); // the char after the last of name
432        
433        /*
434         *Now we have either
435         *~dist(par,par2,..,par83)
436         *or
437         *=expression
438         *or
439         *(index)
440         *or
441         *(index)~dist(par,...)
442         *or
443         *(index)=expr
444         */
445        
446        if (toParse.length() <= 0)
447            throw new SyntaxException("In "+ file +": No column definition, expression or distribution " +
448                    "found for variable on line " + line);
449        
450        if (toParse.charAt(0) == '('){
451            // parse the column definition and parse it out
452            String col = toParse.substring(1, toParse.indexOf(')'));
453            toParse = toParse.substring(toParse.indexOf(')') +1);
454            toAdd.setData(true);
455            if (col.equals("*")) // *, nothing else
456                toAdd.setColumn(-1);
457            else{
458                try{
459                    int temp = Integer.parseInt(col);
460                    if (temp < 1)
461                        throw new SyntaxException("In "+ file +": Invalid column number on line " + line
462                                + " (columns start at 1)");
463                    toAdd.setColumn(temp);
464                }catch (NumberFormatException nfe){
465                    // not *, not an integer, problem
466                    throw new SyntaxException("In "+ file + ": Invalid column number on line " + line);
467                }
468            }
469        } else { // no column def
470            toAdd.setData(false);
471        }
472        
473        
474        // name, column, isData are set
475        
476          /*
477           *Now we have either
478           *~dist(par,par2,..,par83)
479           *or
480           *=expression
481           *or
482           *
483           */
484        
485        
486        if (toParse.length() <= 0)
487            return toAdd;
488        
489         /*
490          *Now we have either
491          *~dist(par,par2,..,par83)
492          *or
493          *=expression
494          */
495        
496        if (toParse.charAt(0) == '~') {
497            toAdd.setFunctional(false);
498            String distStr = null;
499            if (toParse.indexOf('(') < 0)
500                distStr = "";
501            else
502                distStr = toParse.substring(1, toParse.indexOf('(')).trim();
503            Distribution dist = fact.getDistribution(distStr);
504            // this might throw a MissingDistributionException.
505            toAdd.setDistribution(dist);
506            
507            if (toParse.indexOf(')') < 0){
508                throw new SyntaxException("In "+ file +": Mismatching parentheses on line "+ line);
509            }
510            
511            
512            toParse = toParse.substring(toParse.indexOf('(') +1, toParse.lastIndexOf(')')).trim();
513            // Now we have "param1, param2, ..., paramn"
514            
515            if (toParse.length() == 0)
516                throw new SyntaxException("In "+ file +": Too few parameters on line "+ line);
517            
518            int index = 0;
519            while (toParse != null) {
520                int comma = toParse.indexOf(',');
521                String param = null;
522                if (comma > 0) {
523                    param = toParse.substring(0, comma).trim();
524                    // there is a comma, so the next parameter should be before it
525                    // for the next round:
526                    toParse = toParse.substring(comma +1).trim();
527                } else {
528                    param = toParse.trim();
529                    // no comma found, so this is the last parameter
530                    
531                    // to terminate the loop
532                    toParse = null;
533                    
534                    // are there too few parameters in the file?
535                    
536                }
537                
538                // are there too many parameters in the file?
539                if (dist.getNumberOfParameters() <= index)
540                    throw new SyntaxException("In "+ file +": Too many parameters on line "+ line);
541                boolean integer = dist.isInteger(index);
542                if (integer){
543                    try{
544                        int paramInt = Integer.parseInt(param);
545                        dist.setParameter(index, paramInt);
546                        // it's a good integer, no need to check for anything else
547                        
548                    } catch(NumberFormatException e){
549                        // okay, it's not an Integer.
550                        // it may still be a Variable reference
551                        // or something malformed
552                        p = Pattern.compile("[a-z][a-z0-9]*");
553                        
554                        m = p.matcher(param);
555                        if (!m.matches()){
556                            //Ok, it's definitely something malformed.
557                            throw new SyntaxException("In "+ file +": Parameter " + (index +1) +
558                                    " on line " + line + " is not an integer or a correct variable name");
559                        }
560                        Variable paramVar = variableMapper.get(param);
561                        if (paramVar == null) // run out of tricks
562                            throw new SyntaxException("In "+ file +": Parameter " + (index +1) +
563                                    " on line " + line + " is not defined before it is used");
564                        else{
565                            if (!paramVar.isInteger())
566                                throw new SyntaxException("In "+ file +": Parameter " + (index +1) +
567                                        " on line " + line + " is not of type INTEGER");
568                            dist.setParameter(index, paramVar);
569                            paramVar.addAffected(toAdd);
570                            toAdd.addDependence(paramVar);
571                        }
572                    }
573                } else{
574                    // not an integer, so it should be REAL
575                    try {
576                        double paramDouble = Double.parseDouble(param);
577                        dist.setParameter(index, paramDouble);
578                        // it's a good double, continue
579                        
580                    } catch (NumberFormatException nfe){
581                        // okay, not a good double.
582                        
583                        // is it something malformed?
584                        p = Pattern.compile("[a-z][a-z0-9]*");
585                        m = p.matcher(param);
586                        
587                        if (!m.matches()){
588                            //Ok, it's definitely something malformed.
589                            throw new SyntaxException("In "+ file +": Parameter " + (index +1) +
590                                    " on line " + line + " is not a decimal number or a correct " +
591                                    "variable name");
592                        }
593                        
594                        // is it a Variable?
595                        
596                        Variable paramVar = variableMapper.get(param);
597                        if (paramVar == null) // run out of tricks
598                            throw new SyntaxException("In "+ file +": Parameter " + (index +1) +
599                                    " on line " + line + " is not defined before it is used");
600                        else{
601                            // new desireable behaviour: Accept integers on places of REALs,
602                            // consider REAL a more extensive type
603                            /*
604                            if (paramVar.isInteger())
605                                throw new SyntaxException("In "+ file +": Parameter " + (index +1) +
606                                        " on line " + line + " is not of type REAL");
607                             */
608                            dist.setParameter(index, paramVar);
609                            paramVar.addAffected(toAdd);
610                            toAdd.addDependence(paramVar);
611                        }
612                    }
613                    
614                }
615                if (toParse == null){ // if we are going to terminate after this...
616                    if (index+1 != dist.getNumberOfParameters())
617                        throw new SyntaxException("In "+ file +": Too few parameters on line "+ line);
618                }
619                // if we didn't exit yet, the param is good, let's add the
620                // String too
621                dist.setParameterString(index, param);
622                
623                index++;
624            }
625            
626        } else if(toParse.charAt(0) == '=') {
627            toParse = toParse.substring(1).trim();
628            toAdd.setFunctional(true);
629            
630            String equation = toParse;
631            equation = equation.replaceAll("\\p{Space}+", "");
632            
633            ArrayList<String> tempString;
634            ArrayList<Variable> variables;
635            
636            
637            // now we have
638            // EXP(alpha * 12 / LOG(beta - 1.0 * gamma)) ...
639            // we are interested in parts alpha, beta, gamma and their starting indices.
640            // IF I understand correctly, variable names are
641            // the only part here written in lowercase a-z.
642            p = Pattern.compile("[a-z][a-z0-9]*");
643            m = p.matcher(equation);
644            int last = 0;
645            int index = 0;
646            
647            Pattern sum = Pattern.compile("SUM\\(\\&[a-z][a-z0-9]*\\)");
648            Pattern count = Pattern.compile("COUNT\\(\\&[a-z][a-z0-9]*\\)");
649            
650            Matcher sumM = sum.matcher(equation);
651            Matcher countM = count.matcher(equation);
652            
653            tempString = new ArrayList<String>();
654            variables = new ArrayList<Variable>();
655            boolean add = true;
656            
657            if (!sumM.matches() && equation.contains("SUM("))
658                throw new SyntaxException("In " + file + ": 'SUM(&varname)' must be the only " +
659                        "element of an equation if it is used (line " + line +")");
660            if (!countM.matches() && equation.contains("COUNT("))
661                throw new SyntaxException("In " + file + ": 'COUNT(&varname)' must be the only " +
662                        "element of an equation if it is used (line " + line +")");
663            
664            // toAdd is spatial iff the equation matches
665            // either one of the spatial statements.
666            toAdd.setSpatial(sumM.matches() || countM.matches());
667            
668            while (m.find()){
669                add = true;
670                tempString.add(equation.substring(last, m.start()));
671                last = m.end();
672                String newvar = m.group();
673                index++;
674                tempString.add(newvar);
675                for (Variable var : variables){
676                    if (var.getName().equals(newvar))
677                        add = false;
678                }
679                if (add){
680                    if ((equation.indexOf('&') != -1) && equation.indexOf('&') == m.start() -1 ){
681                        // if the variable is preceded with a '&'
682                        // then it is to be checked later.
683                        toBeChecked.add(toAdd);
684                        spatAffectedMap.put(toAdd, newvar);
685                    } else{
686                        Variable dep = variableMapper.get(newvar);
687                        if (dep == null)
688                            throw new SyntaxException("In "+ file +": Variable " + index + " on line " + line
689                                    + " is not defined before it is used");
690                        else{
691                            toAdd.addDependence(dep);
692                            dep.addAffected(toAdd);
693                            variables.add(dep);
694                        }
695                    }
696                }
697            }
698            // note to self: last is the offset AFTER the last match.
699            if (last != equation.length())
700                tempString.add(equation.substring(last));
701            
702            toAdd.setEquation(new Equation(tempString.toArray(new String[tempString.size()]),
703                    variables.toArray(new Variable[variables.size()])));
704            
705        }
706        
707        return toAdd;
708    }
709    
710    /** Reads an entity section in the model file and saves the information into the structures provided.
711     *
712     *
713     */
714    
715    private static void readEntity(File file, LinkedList<Entity> entityList,
716            HashMap<String, Entity> entityMapper, HashMap<String, Variable> variableMapper,
717            String header, Scanner reader, DistributionFactory fact)
718            throws SyntaxException, MissingDistributionException{
719        Entity toAdd = new Entity();
720        
721        // the line we have is an ENTITY definition line.
722        //let's parse it first, and then
723        
724        /* header is:
725           square
726           or
727           square, "squares.txt"
728           or
729           square, "ehkäjotain.txt", "jotain.txt"
730           or
731           squarebird, "observations.txt", combines(square, bird)
732           it can have a { at the line end, or not. let's check that first.
733         */
734        boolean curly = header.indexOf('{') == header.length() -1;
735        int comma = header.indexOf(',');
736        
737        // name , "sth" [, "sth1" || combines(sth2, sth3)]
738        
739        String name = null;
740        
741        if (comma > 0)
742            name = header.substring(0, header.indexOf(',')).trim();
743        else {
744            throw new SyntaxException("In " + file + ": name, \"datafile\" expected on line "+ line);
745        }
746        
747        
748        toAdd.setName(name);
749        
750        String dataFile = null;
751        String spatialFile = null;
752        String x = null;
753        String y = null;
754        
755        comma = header.indexOf(',');
756        
757        header = header.substring(comma +1).trim();
758        // "sth" , "sth1" || combines(sth2,sth3)
759        int caption = header.indexOf('"');
760        if (caption < 0)
761            throw new SyntaxException("In " + file + ": \"datafile\" expected on line " + line);
762        header = header.substring(caption +1).trim();
763        dataFile = header.substring(0, header.indexOf('"')).trim();
764        header = header.substring(header.indexOf('"') +1).trim();
765        if (dataFile.length() == 0)
766            dataFile = null;
767        toAdd.setDataFile(dataFile);
768        
769        
770        
771        //  now dataFile is either null or "something.txt"
772        
773        /*
774          header is:
775          ""
776          or
777          , "sth1"
778          or
779          , combines(sth2, sth3)
780         */
781        
782        comma = header.indexOf(',');
783        if (comma >= 0 && header.length() > 0){ // something more, so header is
784            header = header.substring(header.indexOf(',') +1).trim();
785            /*
786              "sth1"
787              or
788              combines(sth2, sth3)
789             */
790            if (header.startsWith("combines")){
791                toAdd.setMatrix(true);
792                int lparen = header.indexOf('(');
793                int rparen = header.indexOf(')');
794                if (lparen < 0 || rparen < 0)
795                    throw new SyntaxException("Incorrect parentheses after combines-keyword on line "
796                            + line);
797                
798                header = header.substring(lparen +1, rparen).trim();
799                comma = header.indexOf(',');
800                if (comma < 0)
801                    throw new SyntaxException("combines(entity1, entity2) expected on line " + line);
802                
803                y = header.substring(0, comma).trim();
804                x = header.substring(comma +1).trim();
805                Entity yEntity = entityMapper.get(y);
806                Entity xEntity = entityMapper.get(x);
807                
808                if (yEntity == null)
809                    throw new SyntaxException("First entity for combines on line " + line +
810                            " is not defined before it is used");
811                if (xEntity == null)
812                    throw new SyntaxException("Second entity for combines on line " + line +
813                            " is not defined before it is used");
814                
815                toAdd.setYCoordinate(yEntity);
816                toAdd.setXCoordinate(xEntity);
817                
818                
819                
820            } else{ // not a matrix
821                toAdd.setMatrix(false);
822                caption = header.indexOf('"');
823                if (caption < 0)
824                    throw new SyntaxException("\"spatialfile\" expected on line " + line);
825                else{
826                    header = header.substring(caption +1);
827                    caption = header.indexOf('"');
828                    if (caption < 0)
829                        throw new SyntaxException("ending \" missing for \"spatialfile\" on line " + line);
830                    spatialFile = header.substring(0, caption);
831                    toAdd.setSpatialMatrixFile(spatialFile);
832                }
833            }
834        }
835        
836        // now Entity properties name, dataFile, spatialFile, isMatrix, x and y
837        // have been set, if applicable.
838        
839        // continue with the entity structure.
840        String temp;
841        while (reader.hasNextLine()){
842            temp = reader.nextLine();
843            
844            line++;
845            temp = temp.trim();
846            
847            if (temp.length() == 0 || temp.charAt(0) == '#')
848                continue;
849            
850            if (temp.charAt(temp.length() -1) == '}')
851                break;
852            
853            // now we have a non-comment non-zero line.
854            // let's do something brilliant with it.
855            
856            if(!curly)
857                if (temp.charAt(0) == '{'){
858                curly = true;
859                temp = temp.substring(1);
860                if (temp.length() == 0 || temp.charAt(0) == '#')
861                    continue;
862                }
863            
864            if (curly){
865                // do the work
866                
867                // add the Variables to the Entity
868                if (temp.startsWith("REAL")){
869                    temp = temp.substring(4).trim();
870                    Variable var = parseVariable(file, false, temp, variableMapper, fact);
871                    toAdd.addVariable(var);
872                    variableMapper.put(var.getName(), var);
873                    
874                } else if (temp.startsWith("INTEGER")){
875                    temp = temp.substring(7).trim();
876                    Variable var = parseVariable(file, true, temp, variableMapper, fact);
877                    toAdd.addVariable(var);
878                    variableMapper.put(var.getName(), var);
879                } else
880                    throw new SyntaxException("Not a variable inside an entity on line " + line);
881            }
882            
883        }
884        
885        // link the Entity to the Variables
886        for (Variable toLinkUp : toAdd.getVariableList())
887            toLinkUp.setEntity(toAdd);
888        
889        // put the Entity in the map
890        //System.out.println("Adding: " + toAdd.getName());
891        entityMapper.put(toAdd.getName(), toAdd);
892        // link the Entity to the Model
893        entityList.add(toAdd);
894    }
895    
896    
897    /** Reads a simulation parameter file that gives burn-in and thinning. Returns {burn-in, thinning}.
898     *
899     *
900     */
901    
902    private static int[] readSimulation(File file)  throws SyntaxException, IOException{
903        // reads stuff from the file and return burnIn and thinning. (int[2])
904        /*
905          ?? simulation
906          ? burn-in
907          100
908          ? thinning
909          100
910         */
911        return readUnifiedFormatFile(file, "?? simulation", "? burn-in", "? thinning");
912    }
913    
914    /** Reads the update strategy file, saves individual updates (if any) into the variables in the maps,
915     @return {String updateStrategy, int iterations}
916     *
917     *
918     */
919    private static Object[] readUpdate(File file, HashMap<String, Variable> variableMapper,
920            String updateStrategy)  throws SyntaxException, IOException{
921        /* reads the file, parses updateStrategy into the String variable and
922           returns the number of iterations if updateStrategy == sequential.
923           else returns -1, and reads the variables' update numbers.
924         */
925        
926        Object[] toReturn = new Object[2];
927        int iterations = -1;
928        Scanner reader = new Scanner(file);
929        
930        line = 0;
931        String temp = null;
932        updateStrategy = null;
933        boolean rightFile = false;
934        boolean one = false;
935        boolean strategy = false;
936        String fileHeader = "?? update";
937        String headerOne = "? strategy";
938        
939        while (reader.hasNextLine()){
940            temp = reader.nextLine();
941            
942            line++;
943            temp = temp.trim();
944            
945            if (temp.length() == 0 || temp.charAt(0) == '#')
946                continue;
947            
948            if (temp.equals(fileHeader)){
949                rightFile = true;
950                continue;
951            }
952            
953            if (rightFile){
954                if (temp.equals(headerOne)){
955                    one = true;
956                    continue;
957                }
958                
959                if (one && updateStrategy == null){ // updatestrategy header found, read that
960                    updateStrategy = temp;
961                    if (updateStrategy.equals("sequential"))
962                        iterations = readUpdateValues(true, file, reader, variableMapper);
963                    else if (updateStrategy.equals("random"))
964                        iterations = readUpdateValues(false, file, reader, variableMapper);
965                    else
966                        throw new SyntaxException("In "+ file + ": Unknown update strategy on line "
967                                + line);
968                    
969                    continue;
970                } else {
971                    throw new SyntaxException("In "+ file + ": Unknown identifier on line " + line);
972                }
973            } else throw new SyntaxException(("In "+ file + ": File identifier does not match " + fileHeader));
974        }
975        reader.close();
976        
977        toReturn[0] = updateStrategy;
978        toReturn[1] = iterations;
979        return toReturn;
980    }
981    
982    /** Helper for readUpdate.
983     *
984     */
985    private static int readUpdateValues(boolean sequential, File file, Scanner reader,
986            HashMap <String, Variable> variableMapper)   throws SyntaxException {
987        boolean seqHeader = false;
988        String header = null;
989        String temp = null;
990        int iterations = -1;
991        ArrayList<Variable> varArray = new ArrayList<Variable>(variableMapper.values());
992        
993        while (reader.hasNextLine()){
994            temp = reader.nextLine();
995            
996            line++;
997            temp = temp.trim();
998            
999            if (temp.length() == 0 || temp.charAt(0) == '#')
1000                continue;
1001            if (sequential){
1002                if(temp.equals("? iterations")){
1003                    seqHeader = true;
1004                    continue;
1005                }
1006                
1007                if(seqHeader && iterations == -1){ // hasn't been set yet
1008                    try{
1009                        iterations = Integer.parseInt(temp);
1010                    }catch(NumberFormatException e){
1011                        throw new SyntaxException("In "+ file + ": Not an integer on line " + line);
1012                    }
1013                }
1014            } else{
1015                // the hard part:
1016                // expecting:
1017                // ? updates
1018                // 500
1019                // ? varname
1020                // 700
1021                // ? varname
1022                // 600
1023                // ...
1024                if (temp.startsWith("?")){
1025                    header = temp;
1026                    continue;
1027                }
1028                if (header != null){
1029                    int updates = 0;
1030                    try {
1031                        updates = Integer.parseInt(temp);
1032                    }catch(NumberFormatException e){
1033                        throw new SyntaxException("In "+ file + ": Not an integer on line " + line);
1034                    }
1035                    if (header.equals("? updates")){
1036                        for (Variable var : varArray){
1037                            var.setUpdates(updates);
1038                        }
1039                    } else{
1040                        String name = header.substring(1).trim();
1041                        if (name.indexOf(' ') > 0)
1042                            name = name.substring(0, name.indexOf(' ')).trim();
1043                        // if it has "all" or something else after the name
1044                        Variable var = variableMapper.get(name);
1045                        if (var != null)
1046                            var.setUpdates(updates);
1047                        else
1048                            throw new SyntaxException("In "+ file + ": Unknown variable name on line "
1049                                    + line);
1050                    }
1051                    
1052                }
1053            }
1054        }
1055        
1056        return iterations;
1057    }
1058    
1059    /** Helper for readSimulation.
1060     *
1061     */
1062    private static int[] readUnifiedFormatFile(File file, String fileHeader, String headerOne,
1063            String headerTwo) throws SyntaxException, IOException {
1064        Scanner reader = new Scanner(file);
1065        
1066        line = 0;
1067        String temp = null;
1068        boolean rightFile = false;
1069        boolean one = false;
1070        boolean two = false;
1071        int[] toReturn = new int[2];
1072        
1073        while (reader.hasNextLine()){
1074            temp = reader.nextLine();
1075            
1076            line++;
1077            temp = temp.trim();
1078            
1079            if (temp.length() == 0 || temp.charAt(0) == '#')
1080                continue;
1081            
1082            if (temp.equals(fileHeader)){
1083                rightFile = true;
1084                continue;
1085            }
1086            
1087            if (rightFile){
1088                if (temp.equals(headerOne)){
1089                    one = true;
1090                    two = false;
1091                    continue;
1092                }
1093                
1094                if (temp.equals(headerTwo)){
1095                    one = false;
1096                    two = true;
1097                    continue;
1098                }
1099                
1100                if (one){
1101                    try{
1102                        toReturn[0] = Integer.parseInt(temp);
1103                    }catch(NumberFormatException e){
1104                        throw new SyntaxException("In "+ file + ": Not an integer on line " + line);
1105                    }
1106                }
1107                
1108                if (two){
1109                    try{
1110                        toReturn[1] = Integer.parseInt(temp);
1111                    }catch(NumberFormatException e){
1112                        throw new SyntaxException("In "+ file + ": Not an integer on line " + line);
1113                    }
1114                }
1115                
1116            } else throw new SyntaxException(("In "+ file + ": File identifier does not match " + fileHeader));
1117        }
1118        reader.close();
1119        
1120        return toReturn;
1121    }
1122    
1123    /** Reads the parameter names to output -file and sets isPrinted-flags.
1124     *
1125     */
1126    private static String[] readOutput(File file, HashMap<String, Variable> variableMapper)
1127    throws SyntaxException, IOException{
1128        /*
1129        reads the variables to be output from the file,
1130        sets variable.setPrinted() for those variables.
1131         */
1132        
1133        /* expecting:
1134           ?? output
1135           ? alpha
1136           ? x
1137         */
1138        
1139        String[] toReturn = new String[2];
1140        Scanner reader = new Scanner(file);
1141        int line = 0;
1142        String header = null;
1143        String temp = null;
1144        boolean rightFile = false;
1145        String fileHeader = "?? output";
1146        
1147        while (reader.hasNextLine()){
1148            temp = reader.nextLine();
1149            
1150            line++;
1151            temp = temp.trim();
1152            
1153            if (temp.length() == 0 || temp.charAt(0) == '#')
1154                continue;
1155            
1156            if (!rightFile && temp.startsWith(fileHeader)){
1157                rightFile = true;
1158                temp = temp.substring(9); // after ?? output
1159                if (temp.length() > 0){
1160                    StringTokenizer tkn = new StringTokenizer(temp, " ");
1161                    if (tkn.countTokens() != 2)
1162                        throw new SyntaxException("In "+ file + ": ?? output outputFileName " +
1163                                "summaryFileName expected on line "+ line);
1164                    toReturn[0] = tkn.nextToken();
1165                    toReturn[1] = tkn.nextToken();
1166                    
1167                } else
1168                    throw new SyntaxException("In "+ file + ": '?? output outputFileName summaryFileName' " +
1169                            "expected on line "+ line);
1170                continue;
1171            }
1172            if (rightFile){
1173                if (temp.startsWith("?")){
1174                    Variable var = null;
1175                    String all = null;
1176                    String name = temp.substring(1).trim();
1177                    // if it has all after it..
1178                    if (name.indexOf(' ') > 0){
1179                        all = name.substring(name.indexOf(' ')).trim();
1180                        name = name.substring(0, name.indexOf(' ')).trim();
1181                        if (!all.equals(all))
1182                            throw new SyntaxException("In "+ file + ": Expecting '? varname all' or " +
1183                                    "'? varname' on line "+ line);
1184                    }
1185                    var = variableMapper.get(name);
1186                    if (var != null){
1187                        // if the user has not specified 'all' for a nonglobal
1188                        if (all == null && var.getEntity() != null){
1189                            throw new SyntaxException("In "+ file + ": Expecting '? varname all' " +
1190                                    "for a non-global variable on line "+ line);
1191                        }
1192                        var.setPrinted();
1193                    } else
1194                        throw new SyntaxException("In "+ file + ": Unknown variable name on line " + line);
1195                }
1196            } else
1197                throw new SyntaxException(("In "+ file + ": File identifier does not match '" +
1198                        fileHeader +"'"));
1199        }
1200        reader.close();
1201        return toReturn;
1202    }
1203    
1204    /** Reads the proposal distributions/strategies file, sets them for specified variables.
1205     *
1206     */
1207    private static void readProposal(File file, HashMap<String, Variable> variableMapper,
1208            DistributionFactory fact) throws SyntaxException, IOException,
1209            MissingDistributionException{
1210        /* expecting:
1211           ?? proposal distributions
1212           ? alpha
1213           continuous_uniform(-1.0, 1.0)
1214           ? x all
1215           discrete_uniform(0,1)
1216         */
1217        Scanner reader = new Scanner(file);
1218        int line = 0;
1219        String header = null;
1220        String temp = null;
1221        boolean rightFile = false;
1222        String fileHeader = "?? proposal distributions";
1223        
1224        while (reader.hasNextLine()){
1225            temp = reader.nextLine();
1226            
1227            line++;
1228            temp = temp.trim();
1229            
1230            if (temp.length() == 0 || temp.charAt(0) == '#')
1231                continue;
1232            
1233            if (!rightFile && temp.equals(fileHeader)){
1234                rightFile = true;
1235                continue;
1236            }
1237            if (rightFile){
1238                if (temp.startsWith("?")){
1239                    header = temp;
1240                    continue;
1241                }
1242                if (header != null){
1243                    String name = header.substring(1).trim();
1244                    // if it has "all" or other stuff after it
1245                    if (name.indexOf(' ') > 0)
1246                        name = name.substring(0, name.indexOf(' ')).trim();
1247                    Variable var = variableMapper.get(name);
1248                    if (var != null){
1249                        // set the proposal distribution on this line,
1250                        // should match a distribution name.
1251                        // This is copied & modified from parserVariable.
1252                        // allowing proposal distribution parameters to
1253                        // be variables only means uncommenting a few lines.
1254                        // extendability.
1255                        
1256                        String distStr = temp.substring(0, temp.indexOf('(')).trim();
1257                        Distribution dist = fact.getDistribution(distStr);
1258                        // this might throw a MissingDistributionException.
1259                        
1260                        var.setProposal(dist);
1261                        String strategy = temp.substring(temp.lastIndexOf(')') + 1).trim();
1262                        if (strategy.equalsIgnoreCase("RW"))
1263                            var.setStrategy("random walk");
1264                        else
1265                            var.setStrategy("fixed");
1266                        temp = temp.substring(temp.indexOf('(') +1, temp.lastIndexOf(')')).trim();
1267                        // Now we have "param1, param2, ..., paramn"
1268                        
1269                        int index = 0;
1270                        while (temp != null){
1271                            int comma = temp.indexOf(',');
1272                            String param = null;
1273                            if (comma > 0) {
1274                                param = temp.substring(0, comma).trim();
1275                                // there is a comma, so the next parameter should be before it
1276                                // for the next round:
1277                                temp = temp.substring(comma +1).trim();
1278                            } else {
1279                                param = temp.trim();
1280                                // no comma found, so this is the last parameter
1281                                
1282                                // to terminate the loop
1283                                temp = null;
1284                                
1285                                // are there too few parameters in the file?
1286                                if (index+1 != dist.getNumberOfParameters())
1287                                    throw new SyntaxException("Too few parameters on line "+ line);
1288                            }
1289                            
1290                            // are there too many parameters in the file?
1291                            if (dist.getNumberOfParameters() <= index)
1292                                throw new SyntaxException("Too many parameters on line "+ line);
1293                            boolean integer = dist.isInteger(index);
1294                            if (integer){
1295                                try{
1296                                    int paramInt = Integer.parseInt(param);
1297                                    dist.setParameter(index, paramInt);
1298                                    // it's a good integer, no need to check for anything else
1299                                    
1300                                } catch(NumberFormatException e){
1301                                    // okay, it's not an Integer.
1302                                    // it may still be a Variable reference, let's not cry yet
1303                                    /*
1304                                        Variable paramVar = variableMapper.get(param);
1305                                    if (paramVar == null) // run out of tricks
1306                                     throw new SyntaxException("Parameter " + (index +1) + " on line " +
1307                                     line + " Is not defined before it is used");
1308                                     else{
1309                                        dist.setParameter(index, paramVar);
1310                                         paramVar.addAffected(var);
1311                                         var.addDependence(paramVar);
1312                                     */
1313                                    // and comment this:
1314                                    throw new SyntaxException("Proposal distribution has a non-constant " +
1315                                            "parameter " + (index +1) +" on line "+ line);
1316                                }
1317                            } else{
1318                                // not an integer, so it's REAL
1319                                try {
1320                                    double paramDouble = Double.parseDouble(param);
1321                                    dist.setParameter(index, paramDouble);
1322                                    // it's a good double, continue
1323                                    
1324                                } catch (NumberFormatException nfe){
1325                                    // okay, not a good double.
1326                                    
1327                                    // is it a Variable?
1328                                    /*
1329                                      Variable paramVar = variableMapper.get(param);
1330                                      if (paramVar == null) // run out of tricks
1331                                      throw new SyntaxException("Parameter " + (index +1) + " on line "
1332                                     + line + " Is not defined before it is used");
1333                                      else{
1334                                      dist.setParameter(index, paramVar);
1335                                        // paramVar.addAffected(var);
1336                                        // var.addDependence(paramVar);
1337                                     
1338                                     */
1339                                    
1340                                    // and comment this
1341                                    throw new SyntaxException("Proposal distribution has a non-constant " +
1342                                            "parameter " + (index +1) +" on line "+ line);
1343                                }
1344                            }
1345                            
1346                            // if we didn't exit yet, the param is good, let's add the
1347                            // String too
1348                            dist.setParameterString(index, param);
1349                            
1350                            index++;
1351                        }
1352                        
1353                    } else
1354                        throw new SyntaxException("In "+ file + ": Unknown variable name on line " + line);
1355                }
1356            } else
1357                throw new SyntaxException("In "+ file + ": File identifier does not match " + fileHeader);
1358        }
1359        reader.close();
1360        
1361    }
1362    
1363    /** Reads through entities' data files to see if they are correct. builds the missing values matrix files.
1364     *
1365     */
1366    private static void readEntityData(LinkedList<Entity> entityList) throws IOException,
1367            SyntaxException{
1368        /*
1369          Iterate through Entities, all their variables that are data, and
1370          set the data length(s). Since one Entity only has one dataFile,
1371          there are either 0 <= Variables with column > 0,
1372          entailing that only the number of lines in the file counts
1373          (and that all the lines are of equal length)
1374          or one Variable
1375          with column = -1 (taking up the whole dataFile),
1376          entailing that the Entity's XCoordinate and YCoordinate
1377          should get the number of columns and number of lines
1378          as their sizes, respectively.
1379         */
1380        boolean sizeSet = false;
1381        for(Entity e: entityList){
1382            if(e.getDataFile() != null){
1383                readData(e);
1384            }
1385        }
1386    }
1387    
1388    /** Helper for readEntityData.
1389     *
1390     */
1391    private static void readData(Entity e) throws IOException, SyntaxException{
1392        /*
1393           reads the data for a single Entity and sets the fields:
1394           datavar.missingValues, datavar.belongsTo.size
1395           reads out the missing values and writes the datafile_missing.txt
1396           to be used by later methods (readInitialValues)
1397         */
1398        
1399        File dataFile = new File(e.getDataFile());
1400        String dataName = e.getDataFile();
1401        FileWriter data = null;
1402        FileWriter missing = null;
1403        
1404        if (dataName.indexOf('.') < 0)
1405            data = new FileWriter(new File(dataName + "_1.txt"), false);
1406        else
1407            data = new FileWriter(dataName.substring(0, dataName.indexOf('.')) + "_1.txt", false);
1408        
1409        if (dataName.indexOf('.') < 0)
1410            missing = new FileWriter(dataName + "_missing.txt", false);
1411        else
1412            missing = new FileWriter(dataName.substring(0, dataName.indexOf('.')) + "_missing.txt", false);
1413        Scanner reader = new Scanner(dataFile);
1414        int dataVars = 0;
1415        String temp = null;
1416        
1417        for(Variable var : e.getVariableList())
1418            if (var.isData())
1419                dataVars++;
1420        
1421        int[][] cols = new int[dataVars][2]; // {column, type} (0-int, 1-double)
1422        Variable[] dataArray = new Variable[dataVars];
1423        
1424        Variable[] temporary = e.getVariableList().toArray(new Variable[e.getVariableList().size()]);
1425        
1426        dataVars = 0;
1427        for(int i = 0; i < temporary.length; ++i) {
1428            if (temporary[i].isData()){
1429                dataArray[dataVars] = temporary[i];
1430                cols[dataVars][0] = temporary[i].getColumn();
1431                if (temporary[i].isInteger())
1432                    cols[dataVars][1] = 0;
1433                else
1434                    cols[dataVars][1] = 1;
1435                dataVars++;
1436            }
1437        }
1438        
1439        // is this dangerous? I guess not. have to take this up.
1440        for (int i = 0; i < cols.length -1; ++i){
1441            for (int j = i +1; j < cols.length; ++j){
1442                if (cols[i][0] == cols[j][0])
1443                    throw new SyntaxException("Entity "+ e.getName() + " has two variables with the same column number");
1444            }
1445        }
1446        
1447        
1448        line = 0;
1449        int dataline = 0;
1450        int lineLength = 0;
1451        
1452        while (reader.hasNextLine()){
1453            temp = reader.nextLine();
1454            
1455            line++;
1456            temp = temp.trim();
1457            
1458            if (temp.length() == 0 || temp.charAt(0) == '#')
1459                continue;
1460            
1461            StringTokenizer tkn = new StringTokenizer(temp, " ");
1462            if (dataline != 0 && lineLength != tkn.countTokens())
1463                  throw new SyntaxException("In " + dataFile + ": Line " + line + 
1464                          "is of different length than the others");
1465            lineLength = tkn.countTokens();
1466            e.setLineLength(lineLength);
1467            int column = 0;
1468            int index = 0;
1469            String token = null;
1470            while (tkn.hasMoreTokens()){
1471                index = 0;
1472                column++; // columns are numbered starting from 1
1473                token = tkn.nextToken();
1474                
1475                
1476                // there is exactly one variable that can span the whole matrix.
1477                while (index < cols.length-1 && cols[index][0] != -1 && cols[index][0] != column)
1478                    index++;
1479                
1480                if (cols[index][0] != -1 && cols[index][0] != column){
1481                    //  System.out.println("No variable has been defined to use column " + column);
1482                    // write a 0 on its place
1483                    data.write(0 + " ");
1484                    missing.write(1 + " ");
1485                } else{
1486                    // the variable that spans the whole matrix must be matched
1487                    // against every column on every line, logically.
1488                    if (cols[index][0] == column || cols[index][0] == -1){
1489                        //  System.out.println("PARSER DEBUG: matching variable on column " + column);
1490                        
1491                        if (cols[index][1] == 0){ // integer
1492                            //    System.out.println("PARSER DEBUG: (integer)");
1493                            if (token.equals("*")){
1494                                // write a 0 on its place
1495                                data.write(0 + " ");
1496                                missing.write(1 + " ");
1497                                dataArray[index].incrementMissingValues();
1498                            } else{
1499                                try{
1500                                    Integer.parseInt(token);
1501                                    data.write(token + " ");
1502                                    missing.write(0 + " ");
1503                                }catch(NumberFormatException nfe){
1504                                    throw new SyntaxException("In " + dataFile + ": Value on line "+ line +
1505                                            " column " + column + " should be an integer");
1506                                }
1507                            }
1508                        } else{ // decimal(real)
1509                            //  System.out.println("PARSER DEBUG: (real)");
1510                            if (token.equals("*")){
1511                                // write a 0.0 on its place
1512                                data.write(0.0 + " ");
1513                                missing.write(1 + " ");
1514                                dataArray[index].incrementMissingValues();
1515                            } else{
1516                                try{
1517                                    Double.parseDouble(token);
1518                                    data.write(token + " ");
1519                                    missing.write(0 + " ");
1520                                }catch(NumberFormatException nfe){
1521                                    throw new SyntaxException("In " + dataFile + ": Value on line "+ line +
1522                                            " column " + column + " should be a decimal number");
1523                                }
1524                            }
1525                        }
1526                    }
1527                }
1528                
1529            }
1530            missing.write("\n");
1531            data.write("\n");
1532            
1533            dataline++; // do not count comment lines.
1534            
1535        }
1536        reader.close();
1537        missing.close();
1538        data.close();
1539        
1540        for (Variable v: dataArray){
1541            if (v.getMissingValueCount() > 0){
1542                if (v.getDistribution() == null)
1543                    throw new SyntaxException("Variable "+ v.getName() + " has missing values but " +
1544                            "has no distribution");
1545                
1546                if (v.getProposal() == null)
1547                    throw new SyntaxException("Variable "+ v.getName() + " has missing values but " +
1548                            "has no proposal distribution");
1549            }
1550        }
1551        
1552        
1553        if (e.isMatrix()){
1554            
1555            e.getYCoordinate().setSize(dataline);
1556            e.getXCoordinate().setSize(lineLength);
1557            e.setSize(-1);
1558        } else{
1559            e.setSize(dataline);
1560        }
1561    }
1562    
1563    /** Reads the initial values definition file and checks that the format is correct and all missing values of data are present.
1564     *
1565     */
1566    private static void readInitialValues(File file, HashMap<String, Variable> variableMapper)
1567    throws IOException, SyntaxException{
1568        /*
1569          Reads through every Entity,
1570          checks every non-functional Variable that is not data
1571          that is has getEntity().getSize() or if Entity.isMatrix()
1572          getEntity().getYCoordinate().getSize() *
1573          getEntity.getXCoordinate().getSize() initial values in the file.
1574          Checks also for each non-functional Variable that is data and
1575          has missingValueCount > 0
1576          that it has matching indices of initial values
1577          that are set as missing
1578          in the getEntity().dataFile_missing.txt.
1579         */
1580        
1581        /*
1582          expecting:
1583          ?? initial values
1584          ? alpha
1585          0.5
1586          ? x 1:21 1:4
1587          1 2 4 5
1588          1 2 4 6
1589          .......
1590         */
1591        
1592        Scanner reader = new Scanner(file);
1593        String temp = null;
1594        line = 0;
1595        String fileHeader = "?? initial values";
1596        String header = null;
1597        boolean rightFile = false;
1598        
1599        
1600        HashMap<Variable, boolean[][]> missingMap = new HashMap<Variable, boolean[][]>();
1601        // every index of the boolean[][] is information if this is found. (false == missing)
1602        // every variable has got a map like this of its data.
1603        
1604        ArrayList <Variable> varList = new ArrayList<Variable>(variableMapper.values());
1605        
1606        for (Variable v : varList){
1607            if (v.isFunctional())
1608                continue;
1609            if (v.isData() && v.getMissingValueCount() == 0)
1610                continue;
1611            
1612            if (v.isData()){
1613                if (v.getEntity() == null){
1614                    // global variables cannot be data
1615                    throw new SyntaxException("Global variable "+ v.getName() + " has been defined " +
1616                            "as data");
1617                }
1618                
1619                // missing values matrix stuff
1620                Entity entity = v.getEntity();
1621                String dataFileName = entity.getDataFile();
1622                Scanner missread = new Scanner(new File(dataFileName));
1623                String misstemp = null;
1624                int dataline = 0;
1625                boolean[][] missing;
1626                if (entity.isMatrix())
1627                    missing = new boolean[entity.getYCoordinate().getSize()][entity.getXCoordinate().getSize()];
1628                else
1629                    missing = new boolean[entity.getSize()][1];
1630                
1631                while(missread.hasNextLine()){
1632                    misstemp = missread.nextLine().trim();
1633                    dataline++;
1634                    int column = 0;
1635                    String token = null;
1636                    StringTokenizer tkn = new StringTokenizer(misstemp, " ");
1637                    while (tkn.hasMoreTokens()){
1638                        column++;
1639                        token = tkn.nextToken();
1640                        if (token.equals("*"))
1641                            missing[dataline-1][column-1] = false; // missing
1642                        else
1643                            missing[dataline-1][column-1] = true; // found
1644                        
1645                    }
1646                }
1647                
1648                missingMap.put(v, missing);
1649            } else{
1650                if (v.getEntity() == null){
1651                    // global, one value
1652                    boolean[][] missing = new boolean[1][1];
1653                    missing[0][0] = false; // we are missing the one value that has no indices
1654                    missingMap.put(v, missing);
1655                    
1656                } else if (!v.getEntity().isMatrix()){
1657                    // one-dim
1658                    int limit = v.getEntity().getSize();
1659                    // missing every index to size, that is:
1660                    boolean[][] missing = new boolean[limit][1];
1661                    for (int i = 1; i <= limit; ++i)
1662                        missing[i-1][0] = false;
1663                    missingMap.put(v, missing);
1664                } else{
1665                    // two-dim
1666                    int ylimit = v.getEntity().getYCoordinate().getSize();
1667                    int xlimit = v.getEntity().getXCoordinate().getSize();
1668                    
1669                    // missing every index to size, that is:
1670                    boolean[][] missing = new boolean[ylimit][xlimit];
1671                    
1672                    for (int i = 1; i <= ylimit; ++i)
1673                        for (int j = 1; j <= xlimit; ++j)
1674                            missing[i-1][j-1] = false;
1675                    missingMap.put(v, missing);
1676                }
1677            }
1678        }
1679        
1680        while (reader.hasNextLine()){
1681            temp = reader.nextLine().trim();
1682            
1683            line++;
1684            
1685            if (temp.length() == 0 || temp.charAt(0) == '#')
1686                continue;
1687            
1688            if (temp.equals(fileHeader)){
1689                rightFile = true;
1690                continue;
1691            }
1692            
1693            if (rightFile){
1694                if (temp.startsWith("?")){
1695                    header = temp.substring(1).trim();
1696                    continue;
1697                }
1698                if (header != null){
1699                    // alpha [1:12 [1:54]]
1700                    String name = null;
1701                    if (header.indexOf(' ') != -1){
1702                        name = header.substring(0, header.indexOf(' ')).trim();
1703                        header = header.substring(header.indexOf(' ')+1).trim();
1704                    } else {
1705                        name = header.trim();
1706                        header = "";
1707                    }
1708                    // [1:12 [1:54]]
1709                    Variable var = variableMapper.get(name);
1710                    if (var == null)
1711                        throw new SyntaxException("In "+ file + ": Unknown variable name on line " + line);
1712                    else{
1713                        // cases: a global variable:
1714                        // a one-dimensional entity variable
1715                        // a two-dimensional entity variable
1716                        if (var.isFunctional())
1717                            throw new SyntaxException("In "+ file + ": Attempting to give an initial " +
1718                                    "value to a functional variable on line "+ line);
1719                        if (var.isData() && var.getMissingValueCount() == 0)
1720                            throw new SyntaxException("In "+ file + ": Attempting to give an initial " +
1721                                    "value to a data variable on line "+ line);
1722                        
1723                        if (var.getEntity() == null){
1724                            // global, expecting one value
1725                            if (header.length() > 0)
1726                                throw new SyntaxException("In "+ file + ": Unidentified characters " +
1727                                        "after variable name on line "+ line);
1728                            else{
1729                                if (var.isInteger()){
1730                                    try{
1731                                        Integer.parseInt(temp);
1732                                    }catch(NumberFormatException nfe){
1733                                        throw new SyntaxException("In " + file + ": Value on line "+
1734                                                line + " should be an integer");
1735                                    }
1736                                } else{
1737                                    try{
1738                                        Double.parseDouble(temp);
1739                                    }catch(NumberFormatException nfe){
1740                                        throw new SyntaxException("In " + file + ": Value on line "+
1741                                                line + " should be a decimal number");
1742                                    }
1743                                }
1744                                // all is well if we didn't exit yet, and we can:
1745                                missingMap.get(var)[0][0] = true;
1746                            }
1747                        } else if(!var.getEntity().isMatrix()){
1748                            // one-dim
1749                            if (header.indexOf(':') == -1)
1750                                throw new SyntaxException("In " + file + ": '? varname " +
1751                                        "startindex:endindex' " +
1752                                        "expected on line "+ line);
1753                            
1754                            StringTokenizer limt = new StringTokenizer(header, ": ");
1755                            String one = limt.nextToken();
1756                            String two = limt.nextToken();
1757                            int start = -1;
1758                            int end = -1;
1759                            try{
1760                                start = Integer.parseInt(one);
1761                                end = Integer.parseInt(two);
1762                                if (start <= 0 || end <= 0)
1763                                    throw new SyntaxException("In "+ file + ": Boundaries should start from 1 minimum " +
1764                                            "on line "+ line);
1765                            }catch(NumberFormatException nfe){
1766                                throw new SyntaxException("In " + file + ": Boundaries are not integers " +
1767                                        "on line "+ line);
1768                            }
1769                            
1770                            readMissing(file, var.isInteger(), start, end, missingMap.get(var),
1771                                    temp, reader);
1772                            // reads the values from start to end from temp and reader, checks stuff
1773                            // on missingmap to true ([index][2] = 1;)
1774                        } else {
1775                            // two-dim
1776                            StringTokenizer limt = new StringTokenizer(header, ": ");
1777                            if (header.indexOf(':') == -1 || header.indexOf(':') ==
1778                                    header.lastIndexOf(':'))
1779                                throw new SyntaxException("In " + file + ": '? varname " +
1780                                        "ystartindex:yendindex xstartindex:xendindex' expected on line "
1781                                        + line);
1782                            
1783                            String vone = limt.nextToken();
1784                            String vtwo = limt.nextToken();
1785                            String hone = limt.nextToken();
1786                            String htwo = limt.nextToken();
1787                            
1788                            int vstart = -1;
1789                            int vend = -1;
1790                            int hstart = -1;
1791                            int hend = -1;
1792                            try{
1793                                vstart = Integer.parseInt(vone);
1794                                vend = Integer.parseInt(vtwo);
1795                                hstart = Integer.parseInt(hone);
1796                                hend = Integer.parseInt(htwo);
1797                                if (vstart <= 0 || vend <= 0 || hstart <= 0 || hend <= 0)
1798                                    throw new SyntaxException("In "+ file + ": Boundaries should start from 1 minimum " +
1799                                            "on line "+ line);
1800                            }catch(NumberFormatException nfe){
1801                                throw new SyntaxException("In " + file + ": All boundaries are not " +
1802                                        "integers on line "+ line);
1803                            }
1804                            readMissing(file, var.isInteger(), vstart, vend, hstart, hend,
1805                                    missingMap.get(var), temp, reader);
1806                        }
1807                    }
1808                }
1809            } else
1810                throw new SyntaxException("In "+ file + ": File identifier does not match " + fileHeader);
1811            
1812        }
1813        
1814        for (Variable v: varList){
1815            if (v.isFunctional())
1816                continue;
1817            if (v.isData() && v.getMissingValueCount() == 0)
1818                continue;
1819            
1820            boolean[][] missing = missingMap.get(v);
1821            for (int i = 1; i < missing.length; ++i)
1822                for (int j = 1; j < missing[i].length; ++j)
1823                    if (missing[i-1][j-1] == false){
1824                if (v.getEntity() == null)
1825                    throw new SyntaxException("In "+ file + ": Variable "+ v.getName() + " is missing its initial value");
1826                else
1827                    throw new SyntaxException("In "+ file + ": Variable "+ v.getName() + " is missing an initial " +
1828                            "value for ("+ i + ", " + j+ ")");
1829                    }
1830        }
1831        
1832    }
1833    
1834    /** Helper for readInitialValues.
1835     *
1836     */
1837    private static void readMissing(File file, boolean integer, int start, int end,
1838            boolean[][] missing, String temp, Scanner reader)
1839            throws SyntaxException{
1840        readMissing(file, integer, start, end, -1, -1, missing, temp, reader);
1841    }
1842    
1843    /** Helper for readInitialValues.
1844     *
1845     */
1846    private static void readMissing(File file, boolean integer, int vstart, int vend,
1847            int hstart, int hend, boolean[][] missing, String temp, Scanner reader)
1848            throws SyntaxException{
1849        String looptemp = null;
1850        int dataline = vstart;
1851        
1852        while (dataline <= vend){
1853            if (temp != null){
1854                looptemp = temp;
1855                temp = null;
1856            } else{
1857                if (!reader.hasNextLine()){
1858                    if (hstart > 0 && hend > 0)
1859                        throw new SyntaxException("In "+ file +": Not enough initial values, expected "+ vstart +":"+ vend + " "+ hstart + ":" + hend);
1860                    else
1861                        throw new SyntaxException("In "+ file +": Not enough initial values, expected "+ vstart +":"+ vend);
1862                }
1863                looptemp = reader.nextLine().trim();
1864                line++;
1865            }
1866            StringTokenizer tkn = new StringTokenizer(looptemp, " ");
1867            
1868            int column = hstart;
1869            
1870            while (column <= hend){
1871                if (!tkn.hasMoreTokens()){
1872                    if (hstart > 0 && hend > 0)
1873                        throw new SyntaxException("In "+ file +": Not enough initial values, expected "+ vstart +":"+ vend + " "+ hstart + ":" + hend);
1874                    else
1875                        throw new SyntaxException("In "+ file +": Not enough initial values, expected "+ vstart +":"+ vend);
1876                }
1877                
1878                String token = tkn.nextToken();
1879                
1880                if (integer){
1881                    try{
1882                        Integer.parseInt(token);
1883                    }catch(NumberFormatException nfe){
1884                        throw new SyntaxException("In " + file + ": Value " + dataline +", " +
1885                                column + " on line "+ line + " should be an integer");
1886                    }
1887                } else{
1888                    try{
1889                        Double.parseDouble(token);
1890                    }catch(NumberFormatException nfe){
1891                        throw new SyntaxException("In " + file + ": Value " + dataline +", " +
1892                                column + " on line "+ line + " should be a decimal number");
1893                    }
1894                }
1895                
1896                // it is of the correct type now
1897                if (column == -1)
1898                    missing[dataline-1][0] = true;
1899                else
1900                    missing[dataline-1][column -1] = true;
1901                
1902                column++;
1903            }
1904           // System.out.println("data line " + dataline + " parsed");
1905            dataline++;
1906        }
1907        
1908    }
1909    
1910    /** Counts the maximum number of spatial neighbours in the model.
1911     *
1912     */
1913    private static int countNeighbours(LinkedList<Entity> entityList) throws SyntaxException,
1914            FileNotFoundException{
1915        int toReturn = 0;
1916        int spatialEntities = 0;
1917        String spatial = null;
1918        
1919        for (int i = 0; i < entityList.size(); ++i){
1920            Entity e = entityList.get(i);
1921            if (e.getSpatialMatrixFile() != null){
1922                spatial = e.getSpatialMatrixFile();
1923                spatialEntities++;
1924                
1925            }
1926        }
1927        if (spatialEntities > 1)
1928            throw new SyntaxException("More than one spatial entity defined in the model!");
1929        
1930        if (spatialEntities == 0)
1931            return toReturn;
1932        // returning zero, no spatial Entities
1933        
1934        // now we have exactly one spatial entity
1935        // and the matrix filename is at spatial.
1936        
1937        Scanner reader = new Scanner(new File(spatial));
1938        String temp = null;
1939        line = 0;
1940        int maxcount = 0;
1941        int lineLength = 0;
1942        int dataline = 0;
1943        
1944        while (reader.hasNextLine()){
1945            temp = reader.nextLine();
1946            
1947            line++;
1948            temp = temp.trim();
1949            
1950            if (temp.length() == 0 || temp.charAt(0) == '#')
1951                continue;
1952            
1953            StringTokenizer tkn = new StringTokenizer(temp, " ");
1954            if (dataline != 0 && lineLength != tkn.countTokens())
1955                throw new SyntaxException("In " + spatial + ": Line " + line + " is of different " +
1956                        "length than the others");
1957            lineLength = tkn.countTokens();
1958            String token = null;
1959            maxcount = 0;
1960            while (tkn.hasMoreTokens()){
1961                token = tkn.nextToken();
1962                
1963                if (token.equals("1"))
1964                    maxcount++;
1965            }
1966            if (maxcount > toReturn){
1967                
1968                toReturn = maxcount;
1969            }
1970            dataline++; // don't evaluate comment lines
1971            
1972        }
1973        
1974        return toReturn;
1975    }
1976    
1977    /** Runs every variable through a sanity check (see Variable.isOk())
1978     *
1979     
1980     */
1981    private static void checkVariablesAreOk(ArrayList<Variable> variableList)
1982    throws SyntaxException{
1983        for (int i = 0; i < variableList.size()-1; ++i){
1984            for (int j = i +1; j < variableList.size(); ++j){
1985                if (variableList.get(i).equals(variableList.get(j)))
1986                    throw new SyntaxException("Two variables with the same name defined in the model.");
1987            }
1988        }
1989        for(Variable v: variableList){
1990            if (v.getProposal() == null){
1991                if (!v.isFunctional() && !v.isData())
1992                    throw new SyntaxException("Stochastic variable "+v.getName() + " has no proposal " +
1993                            "distribution");
1994            }
1995            if(!v.isOk()){
1996                System.out.println(v);
1997                throw new SyntaxException("Variable "+v.getName() + " is NOT ok");
1998            }
1999        }
2000    }
2001    
2002}

[all classes][PIANOS.io]
EMMA 2.0.5312 (C) Vladimir Roubtsov