You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

516 lines
13 KiB

//==============================================================================
//
// Copyright (c) 2002-
// Authors:
// * Dave Parker <dxp@cs.bham.uc.uk> (University of Birmingham)
// * Andrew Hinton <ug60axh@cs.bham.uc.uk> (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.Vector;
import prism.PrismException;
import prism.PrismUtils;
import simulator.*;
public class ExpressionFunc extends ExpressionNary
{
// codes for each function name
public static final int MIN = 0;
public static final int MAX = 1;
public static final int FLOOR = 2;
public static final int CEIL = 3;
public static final int POW = 4;
public static final int MOD = 5;
public static final int LOG = 6;
// strings for names
public static final String names[] = {"min", "max", "floor", "ceil", "pow", "mod", "log"};
// min/max function arities
public static final int minArities[] = {2, 2, 1, 1, 2, 2, 2};
public static final int maxArities[] = {-1, -1, 1, 1, 2, 2, 2};
// function name
private String name = "";
private int code = -1;
// was function written in old style notation (using built-in keywords)
// (as opposed to new style, i.e. with "func" keyword)
private boolean oldStyle;
// set methods
public void setName(String s)
{
int i, n;
// set string
name = s;
// determine and set code
n = names.length;
code = -1;
for (i = 0; i < n; i++) {
if (s.equals(names[i])) {
code = i;
break;
}
}
}
public void setOldStyle(boolean b)
{
oldStyle = b;
}
// get methods
public String getName()
{
return name;
}
public int getNameCode()
{
return code;
}
public boolean getOldStyle()
{
return oldStyle;
}
// create and return a new expression by renaming
// this includes the function name
public Expression rename(RenamedModule rm) throws PrismException
{
int i, n;
String s;
ExpressionFunc e;
e = new ExpressionFunc();
s = rm.getNewName(name);
s = (s == null) ? name : s;
e.setName(s);
e.setOldStyle(oldStyle);
n = getNumOperands();
for (i = 0; i < n; i++) {
e.addOperand(getOperand(i).rename(rm));
}
return e;
}
// create and return a new expression by expanding constants
public Expression expandConstants(ConstantList constantList) throws PrismException
{
int i, n;
ExpressionFunc e;
e = new ExpressionFunc();
e.setName(getName());
e.setOldStyle(getOldStyle());
n = getNumOperands();
for (i = 0; i < n; i++) {
e.addOperand(getOperand(i).expandConstants(constantList));
}
return e;
}
// check expression is ok
public void check() throws PrismException
{
// check function name is valid
if (code == -1)
throw new PrismException("Unrecognised function \"" + name + "\"");
// check arity
if (getNumOperands() < minArities[code]) {
throw new PrismException("Not enough arguments to \"" + name + "\" function in \"" + this + "\"");
}
if (maxArities[code] != -1 && getNumOperands() > maxArities[code]) {
throw new PrismException("Too many arguments to \"" + name + "\" function in \"" + this + "\"");
}
// check operands
super.check();
}
// type check
public void typeCheck() throws PrismException
{
int i, n, types[];
// check function name is valid
if (code == -1)
throw new PrismException("Unrecognised function \"" + name + "\"");
// compute types of operands
n = getNumOperands();
types = new int[n];
for (i = 0; i < n; i++) {
types[i] = getOperand(i).getType();
}
// check types of operands are ok
switch (code) {
case MIN:
case MAX:
case FLOOR:
case CEIL:
case POW:
case LOG:
// all operands must be ints or doubles
for (i = 0; i < n; i++) {
if (types[i] == Expression.BOOLEAN) {
throw new PrismException("Type error in expression \"" + toString() + "\"");
}
}
break;
case MOD:
// all operands must be ints
for (i = 0; i < n; i++) {
if (types[i] != Expression.INT) {
throw new PrismException("Type error in expression \"" + toString() + "\"");
}
}
break;
}
// determine type of this function
switch (code) {
case MIN:
case MAX:
// int if all ints, double otherwise
for (i = 0; i < n; i++) {
if (types[i] == Expression.DOUBLE) {
setType(Expression.DOUBLE);
return;
}
}
setType(Expression.INT);
break;
case FLOOR:
case CEIL:
case MOD:
// resulting type is always int
setType(Expression.INT);
break;
case POW:
case LOG:
// resulting type is always double
setType(Expression.DOUBLE);
break;
}
}
// evaluate
public Object evaluate(Values constantValues, Values varValues) throws PrismException
{
// check function name is valid
if (code == -1)
throw new PrismException("Unrecognised function \"" + name + "\"");
// split into cases
switch (code) {
case MIN: return evaluateMin(constantValues, varValues);
case MAX: return evaluateMax(constantValues, varValues);
case FLOOR: return evaluateFloor(constantValues, varValues);
case CEIL: return evaluateCeil(constantValues, varValues);
case POW: return evaluatePow(constantValues, varValues);
case MOD: return evaluateMod(constantValues, varValues);
case LOG: return evaluateLog(constantValues, varValues);
default: return null;
}
}
private Object evaluateMin(Values constantValues, Values varValues) throws PrismException
{
int i, j, n, iMin;
double d, dMin;
boolean allInts;
Object o[];
// evaluate operands
n = getNumOperands();
o = new Object[n];
for (i = 0; i < n; i++) {
o[i] = getOperand(i).evaluate(constantValues, varValues);
}
// see if they're all ints
allInts = true;
for (i = 0; i < n; i++) {
if (!(o[i] instanceof Integer)) {
allInts = false;
}
}
// case where all are ints
if (allInts) {
iMin = ((Integer)o[0]).intValue();
n = getNumOperands();
for (i = 1; i < n; i++) {
j = ((Integer)o[i]).intValue();
iMin = (j < iMin) ? j : iMin;
}
return new Integer(iMin);
}
// case where at least one is a double
else {
if (o[0] instanceof Double) {
dMin = ((Double)o[0]).doubleValue();
}
else {
dMin = ((Integer)o[0]).intValue();
}
n = getNumOperands();
for (i = 1; i < n; i++) {
if (o[i] instanceof Double) {
d = ((Double)o[i]).doubleValue();
}
else {
d = ((Integer)o[i]).intValue();
}
dMin = (d < dMin) ? d : dMin;
}
return new Double(dMin);
}
}
public Object evaluateMax(Values constantValues, Values varValues) throws PrismException
{
int i, j, n, iMax;
double d, dMax;
boolean allInts;
Object o[];
// evaluate operands
n = getNumOperands();
o = new Object[n];
for (i = 0; i < n; i++) {
o[i] = getOperand(i).evaluate(constantValues, varValues);
}
// see if they're all ints
allInts = true;
for (i = 0; i < n; i++) {
if (!(o[i] instanceof Integer)) {
allInts = false;
}
}
// case where all are ints
if (allInts) {
iMax = ((Integer)o[0]).intValue();
n = getNumOperands();
for (i = 1; i < n; i++) {
j = ((Integer)o[i]).intValue();
iMax = (j > iMax) ? j : iMax;
}
return new Integer(iMax);
}
// case where at least one is a double
else {
if (o[0] instanceof Double) {
dMax = ((Double)o[0]).doubleValue();
}
else {
dMax = ((Integer)o[0]).intValue();
}
n = getNumOperands();
for (i = 1; i < n; i++) {
if (o[i] instanceof Double) {
d = ((Double)o[i]).doubleValue();
}
else {
d = ((Integer)o[i]).intValue();
}
dMax = (d > dMax) ? d : dMax;
}
return new Double(dMax);
}
}
public Object evaluateFloor(Values constantValues, Values varValues) throws PrismException
{
return new Integer((int)Math.floor(getOperand(0).evaluateDouble(constantValues, varValues)));
}
public Object evaluateCeil(Values constantValues, Values varValues) throws PrismException
{
return new Integer((int)Math.ceil(getOperand(0).evaluateDouble(constantValues, varValues)));
}
public Object evaluatePow(Values constantValues, Values varValues) throws PrismException
{
return new Double(Math.pow(getOperand(0).evaluateDouble(constantValues, varValues), getOperand(1).evaluateDouble(constantValues, varValues)));
}
public Object evaluateMod(Values constantValues, Values varValues) throws PrismException
{
int i = ((Integer)getOperand(0).evaluate(constantValues, varValues)).intValue();
int j = ((Integer)getOperand(1).evaluate(constantValues, varValues)).intValue();
if (j == 0) throw new PrismException("Attempt to compute modulo zero in expression \"" + toString() + "\"");
return new Integer(i % j);
// Object o1, o2;
//
// // evaluate operands
// o1 = getOperand(0).evaluate(constantValues, varValues);
// o2 = getOperand(1).evaluate(constantValues, varValues);
//
// // if both are ints
// if (o1 instanceof Integer && o2 instanceof Integer) {
// return new Integer(((Integer)o1).intValue() % ((Integer)o2).intValue());
// }
// // if either is a double
// else {
// return new Double(((Double)o1).doubleValue() % ((Double)o2).doubleValue());
// }
}
public Object evaluateLog(Values constantValues, Values varValues) throws PrismException
{
double x, b;
x = getOperand(0).evaluateDouble(constantValues, varValues);
b = getOperand(1).evaluateDouble(constantValues, varValues);
return new Double(PrismUtils.log(x, b));
}
/**
* Convert and build simulator expression data structure
*/
public long toSimulator(SimulatorEngine sim) throws SimulatorException
{
try {
switch(code)
{
case MIN:
{
int theType = getType();
int n = getNumOperands();
if( n < 1 )
throw new SimulatorException("Expression \"" + toString() + "\" has zero operands");
long[] exprs = new long[n];
//Collect operands pointers in an array
for (int i = 0; i < n; i++)
exprs[i] = getOperand(i).toSimulator(sim);
//This should be sufficient, providing type
if(theType == Expression.DOUBLE) //checking has been performed
return SimulatorEngine.createRealMin(exprs);
else
return SimulatorEngine.createNormalMin(exprs);
}
case MAX:
{
int theType = getType();
int n = getNumOperands();
if( n < 1 )
throw new SimulatorException("Expression \"" + toString() + "\" has zero operands");
long[] exprs = new long[n];
//Collect operands pointers in an array
for (int i = 0; i < n; i++)
exprs[i] = getOperand(i).toSimulator(sim);
//This should be sufficient, providing type
if(theType == Expression.DOUBLE) //checking has been performed
return SimulatorEngine.createRealMax(exprs);
else
return SimulatorEngine.createNormalMax(exprs);
}
case FLOOR:
{
return SimulatorEngine.createFloor(getOperand(0).toSimulator(sim));
}
case CEIL:
{
return SimulatorEngine.createCeil(getOperand(0).toSimulator(sim));
}
case POW:
{
int theType = getType();
if(theType == Expression.DOUBLE)
{
return SimulatorEngine.createRealPow(getOperand(0).toSimulator(sim), getOperand(1).toSimulator(sim));
}
else
{
return SimulatorEngine.createNormalPow(getOperand(0).toSimulator(sim), getOperand(1).toSimulator(sim));
}
}
case MOD:
{
return SimulatorEngine.createMod(getOperand(0).toSimulator(sim), getOperand(1).toSimulator(sim));
}
case LOG:
{
throw new SimulatorException("The log function is not yet supported in PRISM");
}
default:
throw new SimulatorException("Unrecognised function \"" + name + "\"");
}
}
catch(PrismException e)
{
throw new SimulatorException(e.getMessage());
}
}
// convert to string
public String toString()
{
int i , n;
String s = "";
if (oldStyle) s += name + "(";
else s += "func(" + name + ",";
n = operands.size();
for (i = 0; i < n-1; i++) {
s = s + getOperand(i) + ",";
}
if (n > 0) {
s = s + getOperand(n-1);
}
s += ")";
return s;
}
}
//------------------------------------------------------------------------------