//============================================================================== // // Copyright (c) 2013- // Authors: // * Ernst Moritz Hahn (University of Oxford) // //------------------------------------------------------------------------------ // // 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 param; import java.math.BigInteger; import java.util.HashMap; import java.util.Random; /** * @author Ernst Moritz Hahn (University of Oxford) * TODO complete once needed */ class DagFunctionFactory extends FunctionFactory { private class Number extends DagOperator { private BigInteger number; Number(BigInteger number) { super(number); this.number = number; } BigInteger getNumber() { return number; } @Override public String toString() { return number.toString(); } } private class Variable extends DagOperator { private int variable; Variable(int variable) { super(randomPosition.getDimension(variable).getNum()); this.variable = variable; } int getVariable() { return variable; } @Override public String toString() { return parameterNames[variable]; } } private class Negate extends DagOperator { private DagOperator what; Negate(DagOperator what) { super(what.getCValue().negate()); this.what = what; } DagOperator getWhat() { return what; } @Override public String toString() { return "-(" + what.toString() + ")"; } } private class Add extends DagOperator { private DagOperator op1; private DagOperator op2; Add(DagOperator op1, DagOperator op2) { super(op1.getCValue().add(op2.getCValue())); this.op1 = op1; this.op2 = op2; } DagOperator getOp1() { return op1; } DagOperator getOp2() { return op2; } @Override public String toString() { return "(" + op1.toString() + "+" + op2.toString() + ")"; } } private class Multiply extends DagOperator { private DagOperator op1; private DagOperator op2; Multiply(DagOperator op1, DagOperator op2) { super(op1.getCValue().multiply(op2.getCValue())); this.op1 = op1; this.op2 = op2; } DagOperator getOp1() { return op1; } DagOperator getOp2() { return op2; } @Override public String toString() { return "(" + op1.toString() + "*" + op2.toString() + ")"; } } private Point randomPosition; private HashMap polynomials; private DagOperator zeroOp; private DagOperator oneOp; private DagFunction[] parameters; private DagFunction zero; private DagFunction one; private DagFunction nan; private DagFunction inf; private DagFunction minf; private HashMap functions; // private boolean negateToInner; DagFunctionFactory(String[] parameterNames, BigRational[] lowerBounds, BigRational[] upperBounds, double maxProbWrong, boolean negateToInner) { super(parameterNames, lowerBounds, upperBounds); Random random = new Random(); BigRational[] randomPosArr = new BigRational[parameterNames.length]; int numRandomBits = (int) Math.ceil(Math.log(parameterNames.length / maxProbWrong) / Math.log(2)); for (int dim = 0; dim < parameterNames.length; dim++) { BigInteger num = new BigInteger(numRandomBits, random); randomPosArr[dim] = new BigRational(num, BigInteger.ONE); } randomPosition = new Point(randomPosArr); polynomials = new HashMap(); functions = new HashMap(); zeroOp = new Number(BigInteger.ZERO); polynomials.put(zeroOp,zeroOp); oneOp = new Number(BigInteger.ONE); polynomials.put(oneOp,oneOp); zero = new DagFunction(this, zeroOp, oneOp); functions.put(zero,zero); one = new DagFunction(this, oneOp, oneOp); functions.put(one,one); nan = new DagFunction(this, DagFunction.NAN); functions.put(nan,nan); inf = new DagFunction(this, DagFunction.INF); functions.put(inf,inf); minf = new DagFunction(this, DagFunction.MINF); functions.put(minf,minf); parameters = new DagFunction[parameterNames.length]; for (int varNr = 0; varNr < parameterNames.length; varNr++) { DagOperator paramOp = new Variable(varNr); polynomials.put(paramOp,paramOp); parameters[varNr] = new DagFunction(this, paramOp, oneOp); functions.put(parameters[varNr],parameters[varNr]); } // this.negateToInner = negateToInner; } @Override Function getZero() { return zero; } @Override Function getOne() { return one; } @Override Function getNaN() { return nan; } @Override Function getInf() { return inf; } @Override Function getMInf() { return minf; } private DagOperator makeUnique(DagOperator op) { DagOperator foundOp = polynomials.get(op); if (foundOp == null) { foundOp = op; polynomials.put(foundOp, foundOp); } return foundOp; } private DagFunction makeUnique(DagFunction fn) { DagFunction foundFn = functions.get(fn); if (foundFn == null) { foundFn = fn; functions.put(foundFn, foundFn); } return foundFn; } @Override Function fromBigRational(BigRational bigRat) { bigRat = bigRat.cancel(); DagOperator num = new Number(bigRat.getNum()); num = makeUnique(num); DagOperator den = new Number(bigRat.getDen()); den = makeUnique(den); DagFunction result = new DagFunction(this, num, den); return makeUnique(result); } @Override Function getVar(int var) { return parameters[var]; } private DagOperator opMultiply(DagOperator op1, DagOperator op2) { return makeUnique(new Multiply(op1, op2)); } private DagOperator opAdd(DagOperator op1, DagOperator op2) { return makeUnique(new Add(op1, op2)); } private DagOperator opNegate(DagOperator op) { return makeUnique(new Negate(op)); } public Function add(DagFunction op1, DagFunction op2) { DagOperator num = opAdd(opMultiply(op1.getNum(), op2.getDen()), opMultiply(op1.getDen(), op2.getNum())); DagOperator den = opMultiply(op1.getDen(), op2.getDen()); return makeUnique(new DagFunction(this, num, den)); } public DagFunction negate(DagFunction dagFunction) { DagOperator neg = opNegate(dagFunction.getNum()); return makeUnique(new DagFunction(this, neg, dagFunction.getDen())); } public Function subtract(DagFunction op1, DagFunction op2) { DagFunction negOther = negate(op2); return add(op1, negOther); } public Function multiply(DagFunction op1, DagFunction op2) { DagOperator num = opMultiply(op1.getNum(), op2.getNum()); DagOperator den = opMultiply(op1.getDen(), op2.getDen()); return makeUnique(new DagFunction(this, num, den)); } public Function divide(DagFunction op1, DagFunction op2) { DagOperator num = opMultiply(op1.getNum(), op2.getDen()); DagOperator den = opMultiply(op1.getDen(), op2.getNum()); return makeUnique(new DagFunction(this, num, den)); } public Function star(DagFunction op) { DagOperator num = op.getDen(); DagOperator den = opAdd(op.getDen(), opNegate(op.getNum())); return makeUnique(new DagFunction(this, num, den)); } // TODO fix following public Function toConstraint(DagFunction op) { DagOperator num = op.getNum(); DagOperator den = oneOp; return makeUnique(new DagFunction(this, num, den)); } // TODO use cache for faster evaluation private BigRational evaluate(DagOperator op, Point point) { if (op instanceof Number) { Number opNum = (Number) op; return new BigRational(opNum.getNumber()); } else if (op instanceof Variable) { Variable opVar = (Variable) op; return point.getDimension(opVar.getVariable()); } else if (op instanceof Negate) { Negate opNegate = (Negate) op; return evaluate(opNegate.getWhat(), point).negate(); } else if (op instanceof Add) { Add opAdd = (Add) op; return evaluate(opAdd.getOp1(), point).add(evaluate(opAdd.getOp2(), point)); } else if (op instanceof Multiply) { Multiply opMultiply = (Multiply) op; return evaluate(opMultiply.getOp1(), point).multiply(evaluate(opMultiply.getOp2(), point)); } else { throw new RuntimeException("invalid operator"); } } public BigRational evaluate(DagFunction op, Point point, boolean cancel) { if (op.getType() == DagFunction.NAN) { return BigRational.NAN; } return evaluate(op.getNum(), point).divide(evaluate(op.getDen(), point)); } public BigRational asBigRational(DagFunction op) { BigRational[] point = new BigRational[parameterNames.length]; for (int i = 0; i < parameterNames.length; i++) { point[i] = BigRational.ZERO; } return evaluate(op, new Point(point), true); } public boolean isOne(DagFunction op) { return op == one; } public boolean isZero(DagFunction op) { return op == zero; } public String toString(DagFunction op) { return "(" + op.getNum().toString() + ")/(" + op.getDen().toString() + ")"; } }