public Dictionary <VariableType, UnaryComparison> getReducedUnaryConstraints() { if (!getComparisonExpressions(constraint).All(expr => expr.isUnary())) { throw new PumpingLemmaException("The Language doesn't contain only unary constraints."); } if (!constraint.isSatisfiable()) { throw new PumpingLemmaException("The Language constraint is not satisfiable."); } Dictionary <VariableType, UnaryComparison> comparisonsToReturn = new Dictionary <VariableType, UnaryComparison>(); IEnumerable <ComparisonExpression> allExpr = getComparisonExpressions(constraint); //delete non-constraints allExpr = allExpr.Except(allExpr.Where(e => e.arithmetic_operand1.isConstant() && e.arithmetic_operand2.isConstant())); //put variable on left side //divide, so that coefficient = 1 HashSet <ComparisonExpression> ToDelete = new HashSet <ComparisonExpression>(); var exprToAdd = new HashSet <ComparisonExpression>(); foreach (ComparisonExpression expr in allExpr) { if (expr.arithmetic_operand1.isConstant()) { switch (expr.comparison_operator) { case ComparisonExpression.ComparisonOperator.GEQ: exprToAdd.Add(ComparisonExpression.LessThanOrEqual(expr.arithmetic_operand2, expr.arithmetic_operand1)); break; case ComparisonExpression.ComparisonOperator.GT: exprToAdd.Add(ComparisonExpression.LessThan(expr.arithmetic_operand2, expr.arithmetic_operand1)); break; case ComparisonExpression.ComparisonOperator.LEQ: exprToAdd.Add(ComparisonExpression.GreaterThanOrEqual(expr.arithmetic_operand2, expr.arithmetic_operand1)); break; case ComparisonExpression.ComparisonOperator.LT: exprToAdd.Add(ComparisonExpression.GreaterThan(expr.arithmetic_operand2, expr.arithmetic_operand1)); break; default: break; } } } ToDelete = new HashSet <ComparisonExpression>(allExpr.Where(e => e.arithmetic_operand1.isConstant())); allExpr = allExpr.Except(ToDelete); allExpr = allExpr.Union(exprToAdd); ToDelete = new HashSet <ComparisonExpression>(); exprToAdd = new HashSet <ComparisonExpression>(); foreach (var expr in allExpr) { foreach (VariableType variable in expr.GetVariables()) { int coefficient = expr.arithmetic_operand1.coefficients[variable]; int constant = expr.arithmetic_operand2.constant; double divided = (double)constant / (double)coefficient; switch (expr.comparison_operator) { case ComparisonExpression.ComparisonOperator.EQ: case ComparisonExpression.ComparisonOperator.NEQ: if (!isInt(divided)) { ToDelete.Add(expr); } else { expr.arithmetic_operand2 = LinearIntegerExpression.Constant(Convert.ToInt32(divided)); } break; case ComparisonExpression.ComparisonOperator.GEQ: expr.arithmetic_operand2 = LinearIntegerExpression.Constant(Convert.ToInt32(Math.Ceiling(divided))); break; case ComparisonExpression.ComparisonOperator.GT: expr.arithmetic_operand2 = LinearIntegerExpression.Constant(Convert.ToInt32(Math.Floor(divided))); break; case ComparisonExpression.ComparisonOperator.LEQ: expr.arithmetic_operand2 = LinearIntegerExpression.Constant(Convert.ToInt32(Math.Floor(divided))); break; case ComparisonExpression.ComparisonOperator.LT: expr.arithmetic_operand2 = LinearIntegerExpression.Constant(Convert.ToInt32(Math.Ceiling(divided))); break; default: throw new ArgumentException(); } } } allExpr = allExpr.Except(ToDelete); allExpr = allExpr.Union(exprToAdd); ToDelete = new HashSet <ComparisonExpression>(); exprToAdd = new HashSet <ComparisonExpression>(); //reduce if equal constraint is found HashSet <string> varsToDelete = new HashSet <string>(); foreach (ComparisonExpression expr in allExpr) { if (expr.comparison_operator == ComparisonExpression.ComparisonOperator.EQ) { VariableType variable = expr.arithmetic_operand1.GetVariables().First(); int coefficient = expr.arithmetic_operand1.coefficients[variable]; int constant = expr.arithmetic_operand2.constant; int divided = divideConstant(constant, coefficient); comparisonsToReturn.Add(variable, UnaryComparison.equal(variable, divided)); varsToDelete.Add(variable.ToString()); } } IEnumerable <ComparisonExpression> exprToDelete = allExpr.Where(e => varsToDelete.Contains(e.arithmetic_operand1.GetVariables().First().ToString())); allExpr = allExpr.Except(exprToDelete); //GEQ -> GT, LEQ -> LT exprToDelete = new HashSet <ComparisonExpression>(); exprToAdd = new HashSet <ComparisonExpression>(); foreach (ComparisonExpression expr in allExpr) { if (expr.comparison_operator == ComparisonExpression.ComparisonOperator.GEQ) { ComparisonExpression newExpr = ComparisonExpression.GreaterThan(expr.arithmetic_operand1, expr.arithmetic_operand2.constant - 1); exprToAdd.Add(newExpr); } if (expr.comparison_operator == ComparisonExpression.ComparisonOperator.LEQ) { ComparisonExpression newExpr = ComparisonExpression.LessThan(expr.arithmetic_operand1, expr.arithmetic_operand2.constant + 1); exprToAdd.Add(newExpr); } } exprToDelete = allExpr.Where(e => e.comparison_operator == ComparisonExpression.ComparisonOperator.LEQ || e.comparison_operator == ComparisonExpression.ComparisonOperator.GEQ); allExpr = allExpr.Except(exprToDelete); allExpr = allExpr.Union(exprToAdd); HashSet <VariableType> allVars = new HashSet <VariableType>(); foreach (ComparisonExpression expr in allExpr) { allVars.Add(expr.arithmetic_operand1.GetVariables().First()); } foreach (VariableType variable in allVars) { IEnumerable <ComparisonExpression> varExpr = allExpr.Where(e => variable.ToString().Equals(e.GetVariables().First().ToString())); //reduce to single constraints IEnumerable <ComparisonExpression> gtExpr = varExpr.Where(e => e.comparison_operator == ComparisonExpression.ComparisonOperator.GT); int gthan = -1; foreach (ComparisonExpression expr in gtExpr) { int coefficient = expr.arithmetic_operand1.coefficients[variable]; int constant = expr.arithmetic_operand2.constant; //floor int divided = constant / coefficient; if (constant > gthan) { gthan = constant; } } IEnumerable <ComparisonExpression> ltExpr = varExpr.Where(e => e.comparison_operator == ComparisonExpression.ComparisonOperator.LT); int lthan = Int32.MaxValue; foreach (ComparisonExpression expr in ltExpr) { int coefficient = expr.arithmetic_operand1.coefficients[variable]; int constant = expr.arithmetic_operand2.constant; if (constant < lthan) { lthan = constant; } } varExpr = varExpr.Except(gtExpr); varExpr = varExpr.Except(ltExpr); //rest should be NEQ HashSet <int> neqInts = new HashSet <int>(); foreach (ComparisonExpression expr in varExpr) { if (expr.comparison_operator != ComparisonExpression.ComparisonOperator.NEQ) { throw new PumpingLemmaException("The programmer is stupid."); } int coefficient = expr.arithmetic_operand1.coefficients[variable]; int constant = expr.arithmetic_operand2.constant; double divided = (double)constant / coefficient; //if not int, discard if (Math.Abs(divided % 1) <= (Double.Epsilon * 100)) { int divided_int = (int)divided; neqInts.Add(divided_int); } } if (gthan > -1 && lthan < Int32.MaxValue) { comparisonsToReturn.Add(variable, UnaryComparison.between(variable, gthan, lthan, neqInts)); } else if (gthan > -1 && lthan == Int32.MaxValue) { comparisonsToReturn.Add(variable, UnaryComparison.greater(variable, gthan, neqInts)); } else if (gthan == -1 && lthan < Int32.MaxValue) { comparisonsToReturn.Add(variable, UnaryComparison.between(variable, -1, lthan, neqInts)); } else { comparisonsToReturn.Add(variable, UnaryComparison.greater(variable, -1, neqInts)); } } return(comparisonsToReturn); }
private static UnaryComparison compExprToUnaryComp(ComparisonExpression expr) { if (!expr.isUnary()) { return(null); } if (expr.arithmetic_operand1.isConstant()) { LinearIntegerExpression tmp = expr.arithmetic_operand1; expr.arithmetic_operand1 = expr.arithmetic_operand2; expr.arithmetic_operand2 = tmp; switch (expr.comparison_operator) { case ComparisonExpression.ComparisonOperator.GEQ: expr.comparison_operator = ComparisonExpression.ComparisonOperator.LEQ; break; case ComparisonExpression.ComparisonOperator.GT: expr.comparison_operator = ComparisonExpression.ComparisonOperator.LT; break; case ComparisonExpression.ComparisonOperator.LEQ: expr.comparison_operator = ComparisonExpression.ComparisonOperator.GEQ; break; case ComparisonExpression.ComparisonOperator.LT: expr.comparison_operator = ComparisonExpression.ComparisonOperator.GT; break; default: break; } } VariableType variable = expr.GetVariables().First(); int coefficient = expr.arithmetic_operand1.coefficients[variable]; int constant = expr.arithmetic_operand2.constant; double divided = (double)constant / (double)coefficient; switch (expr.comparison_operator) { case ComparisonExpression.ComparisonOperator.EQ: case ComparisonExpression.ComparisonOperator.NEQ: if (!isInt(divided)) { return(null); } else { expr.arithmetic_operand2 = LinearIntegerExpression.Constant(Convert.ToInt32(divided)); } break; case ComparisonExpression.ComparisonOperator.GEQ: expr.arithmetic_operand2 = LinearIntegerExpression.Constant(Convert.ToInt32(Math.Ceiling(divided))); break; case ComparisonExpression.ComparisonOperator.GT: expr.arithmetic_operand2 = LinearIntegerExpression.Constant(Convert.ToInt32(Math.Floor(divided))); break; case ComparisonExpression.ComparisonOperator.LEQ: expr.arithmetic_operand2 = LinearIntegerExpression.Constant(Convert.ToInt32(Math.Floor(divided))); break; case ComparisonExpression.ComparisonOperator.LT: expr.arithmetic_operand2 = LinearIntegerExpression.Constant(Convert.ToInt32(Math.Ceiling(divided))); break; default: throw new ArgumentException(); } if (expr.comparison_operator == ComparisonExpression.ComparisonOperator.GEQ) { expr.comparison_operator = ComparisonExpression.ComparisonOperator.GT; expr.arithmetic_operand2.constant--; } if (expr.comparison_operator == ComparisonExpression.ComparisonOperator.LEQ) { expr.comparison_operator = ComparisonExpression.ComparisonOperator.LT; expr.arithmetic_operand2.constant++; } switch (expr.comparison_operator) { case ComparisonExpression.ComparisonOperator.EQ: return(UnaryComparison.equal(variable, expr.arithmetic_operand2.constant)); case ComparisonExpression.ComparisonOperator.GT: return(UnaryComparison.greater(variable, expr.arithmetic_operand2.constant, new HashSet <int>())); case ComparisonExpression.ComparisonOperator.LT: return(UnaryComparison.between(variable, -1, expr.arithmetic_operand2.constant, new HashSet <int>())); default: return(null); } }