package cute.concolic.symbolicstate; import cute.concolic.pathconstraint.Constraint; import cute.concolic.Globals; import java.io.PrintWriter; /** * Author: Koushik Sen <ksen@cs.uiuc.edu> */ public class ArithmeticExpression extends Expression implements Constraint { public double[] coeff; public int[] svar; public int type; public double constant; private static final int LE = 1; private static final int GE = 2; public static final int EQ = 3; public static final int NE = 4; private ArithmeticExpression() { } public ArithmeticExpression(int i){ svar = new int[1]; svar[0] = i; coeff = new double[1]; coeff[0] = 1.0; constant = 0.0; } public ArithmeticExpression(ArithmeticExpression from){ constant = from.constant; type = from.type; svar = new int[from.svar.length]; coeff = new double[from.coeff.length]; for (int i = 0; i < coeff.length; i++) { coeff[i] = from.coeff[i]; svar[i] = from.svar[i]; } } public ArithmeticExpression negate() { ArithmeticExpression ret = new ArithmeticExpression(this); ret.constant = - constant; return ret; } public ArithmeticExpression add(ArithmeticExpression second,boolean add) { int count = coeff.length+second.coeff.length; for (int i = 0; i < coeff.length; i++) { for (int j = 0; j < second.coeff.length; j++) { if(svar[i]==second.svar[j]){ count--; if((add && coeff[i]==-second.coeff[j]) || (!add && coeff[i]==second.coeff[j])){ count--; } } } } if(count==0){ return null; } ArithmeticExpression ret = new ArithmeticExpression(); ret.coeff = new double[count]; ret.svar = new int[count]; int k =0; ret.constant = constant; if(add) ret.constant += second.constant; else ret.constant -= second.constant; boolean flag; for (int i = 0; i < coeff.length; i++) { flag = false; for (int j = 0; !flag && j < second.coeff.length; j++) { if(svar[i]==second.svar[j]){ flag = true; } } if(!flag){ ret.coeff[k] = coeff[i]; ret.svar[k] = svar[i]; k++; } } for (int i = 0; i < second.coeff.length; i++) { flag = false; for (int j = 0; !flag && j < coeff.length; j++) { if(svar[i]==second.svar[j]){ flag = true; } } if(!flag){ if(add) ret.coeff[k] = second.coeff[i]; else ret.coeff[k] = -second.coeff[i]; ret.svar[k] = second.svar[i]; k++; } } for (int i = 0; i < coeff.length; i++) { for (int j = 0; j < second.coeff.length; j++) { if(svar[i]==second.svar[j]){ if((add && coeff[i]==-second.coeff[j]) || (!add && coeff[i]==second.coeff[j])){ } else { ret.svar[k] = svar[i]; if(add) ret.coeff[k] = coeff[i]+second.coeff[j]; else ret.coeff[k] = coeff[i]-second.coeff[j]; k++; } } } } return ret; } public ArithmeticExpression add(ArithmeticExpression second) { return add(second,true); } public ArithmeticExpression subtract(ArithmeticExpression second) { return add(second,false); } public ArithmeticExpression multiply(double value) { if(value==0) return null; ArithmeticExpression ret = new ArithmeticExpression(this); for (int i = 0; i < ret.coeff.length; i++) { ret.coeff[i] *= value; } ret.constant *= value; return ret; } public ArithmeticExpression add(double value) { ArithmeticExpression ret = new ArithmeticExpression(this); ret.constant += value; return ret; } public ArithmeticExpression subtractFrom(double value) { ArithmeticExpression ret = new ArithmeticExpression(this); for (int i = 0; i < ret.coeff.length; i++) { ret.coeff[i] = -ret.coeff[i]; } ret.constant = value-ret.constant; return ret; } public ArithmeticExpression subtract(double value) { return add(-value); } public void setL() { type = LE; constant = -(1+constant); } public void setGE() { type = GE; constant = - constant; } public void setG() { type = GE; constant = 1 - constant; } public void setLE() { type = LE; constant = - constant; } public void setEQ() { type = EQ; constant = - constant; } public void setNE() { type = NE; constant = - constant; } public void printExpression(PrintWriter out){ for (int i = 0; i < coeff.length; i++) { if(i!=0){ out.print(" + "); } out.print(coeff[i]); out.print(" x"); out.print(svar[i]); } out.print(" + "); out.println(constant); } public void printConstraint(PrintWriter out){ for (int i = 0; i < coeff.length; i++) { if(i!=0){ out.print(" + "); } out.print(coeff[i]); out.print(" x"); out.print(svar[i]); } if(type==LE) out.print(" <= "); if(type==GE) out.print(" >= "); if(type==EQ) out.print(" == "); if(type==NE) out.print(" != "); out.println(constant); } public void checkValidity(){ double sum = 0; boolean ret = false; for (int i = 0; i < coeff.length; i++) { sum += coeff[i]* Globals.globals.input.getArithInput(svar[i]); } if(type==LE) ret = (sum <= constant); if(type==GE) ret = (sum >= constant); if(type==EQ) ret = (sum == constant); if(type==NE) ret = (sum != constant); if(!ret){ System.err.println("Validity check of contraint failed"); PrintWriter out = new PrintWriter(System.out); printConstraint(out); out.flush(); System.exit(1); } else { PrintWriter out = new PrintWriter(System.out); printConstraint(out); out.flush(); } } public boolean equals(Object obj) { if(!(obj instanceof ArithmeticExpression)) return false; if(this==obj) return true; ArithmeticExpression c1 = this; ArithmeticExpression c2 = (ArithmeticExpression)obj; int i,j,count,t2; boolean first; double times=1.0; first = true; if (c1==null && c2==null) return true; if (c1==null || c2==null) return false; count = c1.svar.length + c2.svar.length; for (i=0;i<c1.svar.length;i++) { for (j=0;j<c2.svar.length;j++) { if (c1.svar[i]== c2.svar[j]) { (count)--; if (first) { first = false; times = c1.coeff[i]/c2.coeff[j]; count--; } else if (c1.coeff[i] == times*c2.coeff[j]) { (count)--; } } } } if (count==0) { t2 = c2.type; if (times<0) { if (t2==GE) t2 = LE; else if (t2==LE) t2 = GE; } if (c1.constant == times * (c2.constant) && (c1.type==t2)) { if (t2==NE && (times != 1 || times != -1)) return false; return true; } } return false; } public void invert() { switch (type) { case GE: type = LE; constant = constant - 1; break; case LE: type = GE; constant = 1 + constant; break; case EQ: type = NE; break; case NE: type = EQ; break; } } public boolean unsat(ArithmeticExpression c2) { int i,j,count,t2; boolean first; double times=1.0; first = true; ArithmeticExpression c1 = this; if (c1==null || c2==null) return false; count = c1.svar.length + c2.svar.length; for (i=0;i<c1.svar.length;i++) { for (j=0;j<c2.svar.length;j++) { if (c1.svar[i] == c2.svar[j]) { (count)--; if (first) { first = false; times = c1.coeff[i] / c2.coeff[j]; count--; } else if (c1.coeff[i] == times*c2.coeff[j]) { (count)--; } } } } if (count==0) { if (c1.constant == times * (c2.constant) && ((c1.type==NE && c2.type==EQ) || (c1.type==EQ && c2.type==NE))) { return true; } if (c1.constant != times * (c2.constant) && (c1.type==EQ && c2.type==EQ)) { return true; } t2 = c2.type; if (times<0) { if (t2==GE) t2 = LE; else if (t2==LE) t2 = GE; } if (c1.constant > times * (c2.constant) && (c1.type==GE && t2==EQ)) { return true; } if (c1.constant > times * (c2.constant) && (c1.type==EQ && t2==LE)) { return true; } if (c1.constant > times * (c2.constant) && (c1.type==GE && t2==LE)) { return true; } if (c1.constant < times * (c2.constant) && (c1.type==LE && t2==EQ)) { return true; } if (c1.constant < times * (c2.constant) && (c1.type==EQ && t2==GE)) { return true; } if (c1.constant < times * (c2.constant) && (c1.type==LE && t2==GE)) { return true; } } return false; } }