//============================================================================== // // Copyright (c) 2002- // Authors: // * Dave Parker (University of Oxford, formerly University of Birmingham) // //------------------------------------------------------------------------------ // // This file is part of PRISM. // // PRISM is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // PRISM is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with PRISM; if not, write to the Free Software Foundation, // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //============================================================================== package parser; import java.util.*; import prism.*; import parser.ast.*; import parser.type.*; /** * Class to store information about the set of variables in a PRISM model. * Assumes that any constants in the model have been given fixed values. * Thus, initial/min/max values for all variables are known. * VarList also takes care of how each variable will be encoded to an integer * (e.g. for (MT)BDD representation). */ public class VarList { // List of variables private List vars; // Mapping from names to indices private Map nameMap; // Total number of bits needed to encode private int totalNumBits; /** * Construct empty variable list. */ public VarList() { vars = new ArrayList(); nameMap = new HashMap(); totalNumBits = 0; } /** * Construct variable list for a ModulesFile. */ public VarList(ModulesFile modulesFile) throws PrismLangException { this(); int i, j, n, n2; parser.ast.Module module; Declaration decl; // First add all globals to the list n = modulesFile.getNumGlobals(); for (i = 0; i < n; i++) { decl = modulesFile.getGlobal(i); addVar(decl, -1, modulesFile.getConstantValues()); } // Then add all module variables to the list n = modulesFile.getNumModules(); for (i = 0; i < n; i++) { module = modulesFile.getModule(i); n2 = module.getNumDeclarations(); for (j = 0; j < n2; j++) { decl = module.getDeclaration(j); addVar(decl, i, modulesFile.getConstantValues()); } } } /** * Add a new variable to the end of the VarList. * @param decl Declaration defining the variable * @param module Index of module containing variable * @param constantValues Values of constants needed to evaluate low/high/etc. */ public void addVar(Declaration decl, int module, Values constantValues) throws PrismLangException { Var var = createVar(decl, module, constantValues); vars.add(var); totalNumBits += getRangeLogTwo(vars.size() - 1); nameMap.put(decl.getName(), vars.size() - 1); } /** * Add a new variable at position i in the VarList. * @param decl Declaration defining the variable * @param module Index of module containing variable * @param constantValues Values of constants needed to evaluate low/high/etc. */ public void addVar(int i, Declaration decl, int module, Values constantValues) throws PrismLangException { Var var = createVar(decl, module, constantValues); vars.add(i, var); totalNumBits += getRangeLogTwo(i); // Recompute name map int j, n; n = getNumVars(); nameMap = new HashMap(n); for (j = 0; j < n; j++) { nameMap.put(getName(j), j); } } /** * Create a new variable object to the store in the list. * @param decl Declaration defining the variable * @param module Index of module containing variable * @param constantValues Values of constants needed to evaluate low/high/etc. */ private Var createVar(Declaration decl, int module, Values constantValues) throws PrismLangException { Var var; int low, high, start; DeclarationType declType; // Create new Var object var = new Var(); // Store name/type/module var.decl = decl; var.module = module; declType = decl.getDeclType(); // Variable is a bounded integer if (declType instanceof DeclarationInt) { DeclarationInt intdecl = (DeclarationInt) declType; low = intdecl.getLow().evaluateInt(constantValues); high = intdecl.getHigh().evaluateInt(constantValues); start = decl.getStartOrDefault().evaluateInt(constantValues); // Check range is valid if (high - low <= 0) { String s = "Invalid range (" + low + "-" + high + ") for variable \"" + decl.getName() + "\""; throw new PrismLangException(s, decl); } if ((long) high - (long) low >= Integer.MAX_VALUE) { String s = "Range for variable \"" + decl.getName() + "\" (" + low + "-" + high + ") is too big"; throw new PrismLangException(s, decl); } // Check start is valid if (start < low || start > high) { String s = "Invalid initial value (" + start + ") for variable \"" + decl.getName() + "\""; throw new PrismLangException(s, decl); } } // Variable is a Boolean else if (declType instanceof DeclarationBool) { low = 0; high = 1; start = (decl.getStartOrDefault().evaluateBoolean(constantValues)) ? 1 : 0; } // Variable is a clock else if (declType instanceof DeclarationClock) { // Create dummy info low = 0; high = 1; start = 0; } // Variable is an (unbounded) integer else if (declType instanceof DeclarationIntUnbounded) { // Create dummy range info low = 0; high = 1; start = decl.getStartOrDefault().evaluateInt(constantValues); } else { throw new PrismLangException("Unknown variable type \"" + declType + "\" in declaration", decl); } // Store low/high/start and return var.low = low; var.high = high; var.start = start; return var; } /** * Get the number of variables stored in this list. */ public int getNumVars() { return vars.size(); } /** * Look up the index of a variable, as stored in this list, by name. * Returns -1 if there is no such variable. */ public int getIndex(String name) { Integer i = nameMap.get(name); return (i == null) ? -1 : i; } /** * Check if there is a variable of a given name in this list. */ public boolean exists(String name) { return getIndex(name) != -1; } /** * Get the declaration of the ith variable in this list. */ public Declaration getDeclaration(int i) { return vars.get(i).decl; } /** * Get the index in this VarList for a given declaration. */ public int getIndexFromDeclaration(Declaration d) { for (int i=0;i getAllValues(List vars) throws PrismLangException { int i, j, k, n, lo, hi; Vector allValues; Values vals, valsNew; allValues = new Vector(); allValues.add(new Values()); for (String var : vars) { i = getIndex(var); if (getType(i) instanceof TypeBool) { n = allValues.size(); for (j = 0; j < n; j++) { vals = allValues.get(j); valsNew = new Values(vals); valsNew.setValue(var, true); allValues.add(valsNew); vals.addValue(var, false); } } else if (getType(i) instanceof TypeInt) { lo = getLow(i); hi = getHigh(i); n = allValues.size(); for (j = 0; j < n; j++) { vals = allValues.get(j); for (k = lo + 1; k < hi + 1; k++) { valsNew = new Values(vals); valsNew.setValue(var, k); allValues.add(valsNew); } vals.addValue(var, lo); } } else { throw new PrismLangException("Cannot determine all values for a variable of type " + getType(i)); } } return allValues; } /** * Get a list of all possible states over the variables in this list. Use with care! */ public List getAllStates() throws PrismLangException { List allStates; State state, stateNew; int numVars = getNumVars(); allStates = new ArrayList(); allStates.add(new State(numVars)); for (int i = 0; i < numVars; i++) { if (getType(i) instanceof TypeBool) { int n = allStates.size(); for (int j = 0; j < n; j++) { state = allStates.get(j); stateNew = new State(state); stateNew.setValue(i, true); state.setValue(i, false); allStates.add(stateNew); } } else if (getType(i) instanceof TypeInt) { int lo = getLow(i); int hi = getHigh(i); int n = allStates.size(); for (int j = 0; j < n; j++) { state = allStates.get(j); for (int k = lo + 1; k < hi + 1; k++) { stateNew = new State(state); stateNew.setValue(i, k); allStates.add(stateNew); } state.setValue(i, lo); } } else { throw new PrismLangException("Cannot determine all values for a variable of type " + getType(i)); } } return allStates; } /** * Convert a bit vector representing a single state to a State object. */ public State convertBitSetToState(BitSet bits) { int i, n, j, var, val; State state; state = new State(getNumVars()); var = val = j = 0; n = totalNumBits; for (i = 0; i < n; i++) { if (bits.get(i)) val += (1 << (getRangeLogTwo(var) - j - 1)); if (j >= getRangeLogTwo(var) - 1) { state.setValue(var, decodeFromInt(var, val)); var++; val = 0; j = 0; } else { j++; } } return state; } /** * Clone this list. */ public Object clone() { int i, n; n = getNumVars(); VarList rv = new VarList(); rv.vars = new ArrayList(n); rv.nameMap = new HashMap(n); for (i = 0; i < n; i++) { rv.vars.add(new Var(vars.get(i))); rv.nameMap.put(getName(i), i); } return rv; } /** * Class to store information about a single variable. */ class Var { // Basic info (name/type/etc.) stored as Declaration public Declaration decl; // Index of containing module (-1 for a global) public int module; // Info about how variable is encoded as an integer public int low; public int high; public int start; // Default constructor public Var() { } // Copy constructor public Var(Var var) { decl = (Declaration) var.decl.deepCopy(); module = var.module; low = var.low; high = var.high; start = var.start; } } }