org.sosy_lab.cpachecker.cpa.chc.ConstraintManager.java Source code

Java tutorial

Introduction

Here is the source code for org.sosy_lab.cpachecker.cpa.chc.ConstraintManager.java

Source

/*
 *  CPAchecker is a tool for configurable software verification.
 *  This file is part of CPAchecker.
 *
 *  Copyright (C) 2007-2014  Dirk Beyer
 *  All rights reserved.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *
 *  CPAchecker web page:
 *    http://cpachecker.sosy-lab.org
 */
package org.sosy_lab.cpachecker.cpa.chc;

import com.google.common.collect.Lists;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;

import org.sosy_lab.common.log.LogManager;
import org.sosy_lab.cpachecker.cfa.ast.AExpression;
import org.sosy_lab.cpachecker.cfa.ast.AFunctionCall;
import org.sosy_lab.cpachecker.cfa.ast.AFunctionCallAssignmentStatement;
import org.sosy_lab.cpachecker.cfa.ast.AIdExpression;
import org.sosy_lab.cpachecker.cfa.ast.AInitializer;
import org.sosy_lab.cpachecker.cfa.ast.c.CArraySubscriptExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CAssignment;
import org.sosy_lab.cpachecker.cfa.ast.c.CBinaryExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CBinaryExpression.BinaryOperator;
import org.sosy_lab.cpachecker.cfa.ast.c.CDeclaration;
import org.sosy_lab.cpachecker.cfa.ast.c.CExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CFieldReference;
import org.sosy_lab.cpachecker.cfa.ast.c.CFunctionCallExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CIdExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CInitializerExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CIntegerLiteralExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CRightHandSide;
import org.sosy_lab.cpachecker.cfa.ast.c.CVariableDeclaration;
import org.sosy_lab.cpachecker.cfa.model.ADeclarationEdge;
import org.sosy_lab.cpachecker.cfa.model.AReturnStatementEdge;
import org.sosy_lab.cpachecker.cfa.model.AssumeEdge;
import org.sosy_lab.cpachecker.cfa.model.FunctionReturnEdge;
import org.sosy_lab.cpachecker.cfa.model.FunctionSummaryEdge;
import org.sosy_lab.cpachecker.exceptions.UnrecognizedCCodeException;
import org.sosy_lab.cpachecker.util.Pair;

import jpl.Compound;
import jpl.JPL;
import jpl.Query;
import jpl.Term;
import jpl.Util;
import jpl.Variable;

public class ConstraintManager {

    private static LogManager logger;

    public static boolean init(String firingRelation, String generalizationOperator, LogManager logM) {

        String initstr[] = { "swipl", "-x", "./lib/native/x86_64-linux/chc_lib", "-g", "true", "-nosignals" };

        boolean init = JPL.init(initstr);

        initFiringRelation(firingRelation);
        initGeneralizationOperator(generalizationOperator);
        logger = logM;

        return init;
    }

    public static Constraint simplify(ArrayList<Term> cn, HashMap<String, Term> vars) {

        // Constraint to be solved
        Term constraint = Util.termArrayToList(cn.toArray(new Term[0]));
        // Create a list of variable to solve the constraint
        Term varList = Util.termArrayToList(vars.values().toArray(new Term[0]));
        // Solve constraint w.r.t. variables occurring in varList
        Term args[] = { constraint, varList, new Variable("S") };
        Query q = new Query("solve", args);

        logger.log(Level.FINEST, "\n * solve (w.r.t. " + varList.toString() + ")");

        @SuppressWarnings("unchecked")
        Hashtable<String, Term> sol = q.oneSolution();

        return ConstraintManager.normalize("S", sol);
    }

    public static boolean subsumes(Constraint cn1, Constraint cn2) {

        // Constraint 1
        Term constraint1 = Util.termArrayToList(cn1.getConstraint().toArray(new Term[0]));
        // Constraint 2
        Term constraint2 = Util.termArrayToList(cn2.getConstraint().toArray(new Term[0]));

        Term args[] = { constraint1, constraint2 };

        Query q = new Query("entails", args);

        logger.log(Level.FINEST, "\n * " + cn1.toString() + "\n * entails" + "\n * " + cn2.toString() + ")");

        boolean res = q.hasSolution();

        logger.log(Level.FINEST, "\n * result: " + res);

        return res;
    }

    @SuppressWarnings("unchecked")
    public static Constraint generalize(Constraint cn1, Constraint cn2) {

        // Constraint 1
        Term constraint1 = Util.termArrayToList(cn1.getConstraint().toArray(new Term[0]));
        // Constraint 2
        Term constraint2 = Util.termArrayToList(cn2.getConstraint().toArray(new Term[0]));

        Term args[] = { constraint1, constraint2, new Variable("G") };

        Query q = new Query("generalize", args);

        logger.log(Level.FINEST, "\n * definition: " + cn1.toString() + "\n * ancestor :  " + cn1.toString());

        return normalize("G", q.oneSolution());
    }

    public static Constraint and(Constraint cn1, Constraint cn2) {

        ArrayList<Term> andCn = new ArrayList<>(cn1.getConstraint());
        andCn.addAll(cn2.getConstraint());

        logger.log(Level.FINEST, "\n * " + cn1.toString() + "\n * and \n * " + cn2.toString());

        /*
         * create a list of variable to solve the constraint
         * Remove all non primed variables which occur in
         * the set of primed variables
         */
        HashMap<String, Term> newVars = ConstraintManager.selectVariables(cn1.getVars(), cn2.getVars());

        Constraint andConstraint = ConstraintManager.simplify(andCn, newVars);

        logger.log(Level.FINEST, "\n * " + andConstraint.toString());

        return andConstraint;
    }

    private static HashMap<String, Term> selectVariables(HashMap<String, Term> vars, HashMap<String, Term> pVars) {

        HashMap<String, Term> newVars = new HashMap<>(pVars);

        for (Map.Entry<String, Term> me : vars.entrySet()) {
            if (!pVars.containsKey(me.getKey())) {
                newVars.put(me.getKey(), me.getValue());
            }
        }

        return newVars;
    }

    private static Constraint normalize(String sol, Hashtable<String, Term> varMap) {

        // fetches the solution
        Term cn = varMap.get(sol);

        String newConstraint = cn.toString();

        Constraint nres = new Constraint();

        if (Constraint.isFalse(newConstraint)) {
            return nres.setFalse();
        }

        Hashtable<String, Term> varSolMap = new Hashtable<>(varMap);

        varSolMap.remove(sol);

        /*
         * replace all occurrences of primed variables
         * by their corresponding unprimed version
         */
        for (Map.Entry<String, Term> me : varSolMap.entrySet()) {
            newConstraint = newConstraint.replaceAll(me.getValue().toString(),
                    ConstraintManager.primedVarToVar(me.getKey()));
            nres.addVar(var2CVar(ConstraintManager.primedVarToVar(me.getKey())),
                    new Variable(primedVarToVar(me.getKey())));
        }

        // TODO: to be improved
        nres.setConstraint(new ArrayList<>(Arrays.asList(Util.listToTermArray(Util.textToTerm(newConstraint)))));

        logger.log(Level.FINEST, "\n * result: " + nres.toString());

        return nres;
    }

    public static ArrayList<Constraint> getConstraint(AssumeEdge ae) {
        CBinaryExpression c = (CBinaryExpression) (ae.getExpression());
        Collection<Pair<Term, ArrayList<Term>>> acList;
        ArrayList<Constraint> cns = new ArrayList<>(2);

        if (ae.getTruthAssumption()) {
            // atomic constraint
            acList = expressionToCLP(c);
            // for all term in the list create a constraint
            for (Pair<Term, ArrayList<Term>> p : acList) {
                cns.add(new Constraint(p.getFirst(), p.getSecond()));
            }
        } else {
            // negated atomic constraint
            CBinaryExpression negbe = getNegatedRelOperator(c);
            acList = expressionToCLP(negbe);
            for (Pair<Term, ArrayList<Term>> p : acList) {
                cns.add(new Constraint(p.getFirst(), p.getSecond()));
            }
        }

        return cns;
    }

    public static Constraint getConstraint(CAssignment ca) {
        Constraint c = new Constraint();
        CExpression lhs = ca.getLeftHandSide();
        CRightHandSide rhs = ca.getRightHandSide();
        CExpression exp = (CExpression) rhs;
        c.addVar(lhs.toString(), ConstraintManager.CVar2PrologPrimedVar(lhs.toString()));
        if (lhs instanceof AIdExpression) {
            for (Pair<Term, ArrayList<Term>> t : expressionToCLP(exp)) {
                Term[] operands = { c.getVars().get(lhs.toString()), t.getFirst() };
                ArrayList<Term> list = new ArrayList<>();
                list.add(new Compound("=:=", operands));
                c.setConstraint(list);
            }
        } else {
            throw new AssertionError("unhandled assignment " + ca.toString());
        }
        return c;
    }

    public static Constraint getConstraint(CExpression exp) {
        ArrayList<Term> tlist = new ArrayList<>();
        ArrayList<Term> vlist = new ArrayList<>();
        for (Pair<Term, ArrayList<Term>> t : expressionToCLP(exp)) {
            tlist.add(t.getFirst());
            vlist.addAll(t.getSecond());
        }
        return new Constraint(tlist, vlist);
    }

    public static ArrayList<Constraint> getConstraint(List<CExpression> exp) {
        ArrayList<Constraint> clist = new ArrayList<>();
        for (CExpression c : exp) {
            clist.add(getConstraint(c));
        }
        return clist;
    }

    public static Constraint getConstraint(ADeclarationEdge ae) {
        CDeclaration decl = (CDeclaration) ae.getDeclaration();
        Constraint ac = new Constraint();
        if (decl instanceof CVariableDeclaration) {
            CVariableDeclaration vdecl = (CVariableDeclaration) decl;
            AInitializer initializer = vdecl.getInitializer();
            String varName = vdecl.getName();
            Term lhs = CVar2PrologPrimedVar(varName);
            if (initializer != null) {
                if (initializer instanceof CInitializerExpression) {
                    CExpression expression = ((CInitializerExpression) initializer).getExpression();
                    Collection<Pair<Term, ArrayList<Term>>> at = expressionToCLP(expression);
                    for (Pair<Term, ArrayList<Term>> t : at) {
                        Term rhs = t.getFirst();
                        ArrayList<Term> acList = new ArrayList<>();
                        acList.add(new Compound("=:=", new Term[] { lhs, rhs }));
                        ac.setConstraint(acList);
                    }
                }
            }
            ac.addVar(varName, lhs);
        }
        return ac;
    }

    public static Constraint getConstraint(AReturnStatementEdge aRetEdge) {

        AExpression expression = aRetEdge.getExpression().isPresent() ? aRetEdge.getExpression().get()
                : CIntegerLiteralExpression.ZERO; // this is the default in C

        String varName = "FRET_" + aRetEdge.getSuccessor().getFunctionName();

        Term lhs = CVar2PrologVar(varName);

        Constraint ac = new Constraint();

        Collection<Pair<Term, ArrayList<Term>>> at = expressionToCLP(expression);
        for (Pair<Term, ArrayList<Term>> t : at) {
            Term rhs = t.getFirst();
            ArrayList<Term> acList = new ArrayList<>();
            acList.add(new Compound("=:=", new Term[] { lhs, rhs }));
            ac.setConstraint(acList);
        }

        ac.addVar(varName, lhs);

        return ac;
    }

    public static Constraint getConstraint(FunctionReturnEdge fretEdge) throws UnrecognizedCCodeException {

        FunctionSummaryEdge summaryEdge = fretEdge.getSummaryEdge();
        AFunctionCall exprOnSummary = summaryEdge.getExpression();

        // expression is an assignment operation, e.g. a = g(b);
        if (exprOnSummary instanceof AFunctionCallAssignmentStatement) {
            AFunctionCallAssignmentStatement assignExp = ((AFunctionCallAssignmentStatement) exprOnSummary);
            AExpression op1 = assignExp.getLeftHandSide();

            // we expect left hand side of the expression to be a variable
            if ((op1 instanceof AIdExpression) || (op1 instanceof CFieldReference)) {

                String varName = "FRET_" + fretEdge.getPredecessor().getFunctionName();
                Term lhs = CVar2PrologPrimedVar(op1.toString());
                Term rhs = CVar2PrologVar(varName);
                Constraint ac = new Constraint(Lists.newArrayList(new Compound("=:=", new Term[] { lhs, rhs })));

                ac.addVar(op1.toString(), lhs);

                return ac;
            }
            // TODO: a[x] = b();
            else if (op1 instanceof CArraySubscriptExpression) {
                return new Constraint();
            } else {
                throw new UnrecognizedCCodeException("on function return", summaryEdge, null);
            }
        }
        return new Constraint();
    }

    public static Constraint getConstraint(CExpression lhs, CFunctionCallExpression rhs) {
        Constraint c = new Constraint();
        if (rhs != null) {
            c.addVar(lhs.toString(), ConstraintManager.CVar2PrologPrimedVar(lhs.toString()));
            if (lhs instanceof AIdExpression) {
                Term[] operands = { c.getVars().get(lhs.toString()),
                        CVar2PrologVar(rhs.getFunctionNameExpression().toString()) };
                ArrayList<Term> list = new ArrayList<>();
                list.add(new Compound("=:=", operands));
                c.setConstraint(list);
            }
        }
        return c;
    }

    public static Collection<Constraint> getConstraint(List<String> names,
            List<? extends AExpression> expressions) {

        ArrayList<Constraint> cnList = new ArrayList<>();

        for (int i = 0; i < names.size(); i++) {

            String name = names.get(i);
            AExpression expression = expressions.get(i);

            for (Pair<Term, ArrayList<Term>> p : paramExpressionToCLP(name, expression)) {
                cnList.add(new Constraint(new ArrayList<>(Arrays.asList(Util.listToTermArray(p.getFirst()))),
                        p.getSecond()));
            }
        }

        return cnList;
    }

    /**
     * input:  ppv is of the form "_$CVAR", where
     *         $CVAR stands for a C program variable
     * output: "$CVAR"
     */
    public static String var2CVar(String pv) {
        return pv.substring(4);
    }

    /**
     * input:  ppv is of the form "_p_$CVAR", where
     *         $CVAR stands for a C program variable
     * output: "$CVAR"
     */
    public static String primedVar2CVar(String ppv) {
        return ppv.substring(11);
    }

    public static Variable CVar2PrologVar(String cv) {
        return new Variable("CPA_" + cv);
    }

    public static Variable CVar2PrologPrimedVar(String cv) {
        return new Variable("Primed_CPA_" + cv);
    }

    private static String primedVarToVar(String pvar) {
        if (pvar.startsWith("Primed_")) {
            return pvar.replace("Primed_", "");
        }
        return pvar;
    }

    private static Collection<Pair<Term, ArrayList<Term>>> getNegatedConstraintList(
            Pair<Term, ArrayList<Term>> cn) {

        Compound atomCnT = (Compound) cn.getFirst();
        Compound negAtomCnT = null;
        switch (atomCnT.name()) {
        case "<":
            negAtomCnT = new Compound(">=", 2);
            negAtomCnT.setArg(1, atomCnT.arg(1));
            negAtomCnT.setArg(2, atomCnT.arg(2));
            return Collections.singleton(Pair.of((Term) negAtomCnT, cn.getSecond()));
        case "=<":
            negAtomCnT = new Compound(">", 2);
            negAtomCnT.setArg(1, atomCnT.arg(1));
            negAtomCnT.setArg(2, atomCnT.arg(2));
            return Collections.singleton(Pair.of((Term) negAtomCnT, cn.getSecond()));
        case ">":
            negAtomCnT = new Compound("=<", 2);
            negAtomCnT.setArg(1, atomCnT.arg(1));
            negAtomCnT.setArg(2, atomCnT.arg(2));
            return Collections.singleton(Pair.of((Term) negAtomCnT, cn.getSecond()));
        case ">=":
            negAtomCnT = new Compound("<", 2);
            negAtomCnT.setArg(1, atomCnT.arg(1));
            negAtomCnT.setArg(2, atomCnT.arg(2));
            return Collections.singleton(Pair.of((Term) negAtomCnT, cn.getSecond()));
        case "=:=":
            return Arrays.asList(
                    Pair.of((Term) new Compound("<", new Term[] { atomCnT.arg(1), atomCnT.arg(2) }),
                            cn.getSecond()),
                    Pair.of((Term) new Compound(">", new Term[] { atomCnT.arg(1), atomCnT.arg(2) }),
                            cn.getSecond()));
        default:
            return null;
        }
    }

    private static CBinaryExpression getNegatedRelOperator(CBinaryExpression be) {

        switch (be.getOperator()) {
        case EQUALS:
            return new CBinaryExpression(be.getFileLocation(), be.getExpressionType(), be.getCalculationType(),
                    be.getOperand1(), be.getOperand2(), BinaryOperator.NOT_EQUALS);
        case NOT_EQUALS:
            return new CBinaryExpression(be.getFileLocation(), be.getExpressionType(), be.getCalculationType(),
                    be.getOperand1(), be.getOperand2(), BinaryOperator.EQUALS);
        case LESS_THAN:
            return new CBinaryExpression(be.getFileLocation(), be.getExpressionType(), be.getCalculationType(),
                    be.getOperand1(), be.getOperand2(), BinaryOperator.GREATER_EQUAL);
        case LESS_EQUAL:
            return new CBinaryExpression(be.getFileLocation(), be.getExpressionType(), be.getCalculationType(),
                    be.getOperand1(), be.getOperand2(), BinaryOperator.GREATER_THAN);
        case GREATER_THAN:
            return new CBinaryExpression(be.getFileLocation(), be.getExpressionType(), be.getCalculationType(),
                    be.getOperand1(), be.getOperand2(), BinaryOperator.LESS_EQUAL);
        case GREATER_EQUAL:
            return new CBinaryExpression(be.getFileLocation(), be.getExpressionType(), be.getCalculationType(),
                    be.getOperand1(), be.getOperand2(), BinaryOperator.LESS_THAN);
        default: // not a relational operator
            return null;
        }
    }

    private static Collection<Pair<Term, ArrayList<Term>>> expressionToCLP(AExpression ce) {

        ArrayList<Term> vars = new ArrayList<>();

        if (ce instanceof CIdExpression) {
            vars.add(CVar2PrologVar(ce.toString()));
            return Collections.singleton(Pair.of((Term) CVar2PrologVar(ce.toString()), vars));
        } else if (ce instanceof CIntegerLiteralExpression) {
            return Collections.singleton(Pair.of(Util.textToTerm("rdiv(" + ce.toString() + ",1)"), vars));
        } else if (ce instanceof CBinaryExpression) {
            CBinaryExpression bexp = (CBinaryExpression) ce;
            Collection<Pair<Term, ArrayList<Term>>> operand1 = expressionToCLP(bexp.getOperand1());
            Collection<Pair<Term, ArrayList<Term>>> operand2 = expressionToCLP(bexp.getOperand2());
            switch (bexp.getOperator()) {
            case PLUS:
                return addOperands("+", operand1, operand2);
            case MINUS:
                return addOperands("-", operand1, operand2);
            case MULTIPLY:
                return addOperands("*", operand1, operand2);
            case DIVIDE:
                return addOperands("/", operand1, operand2);
            case EQUALS:
                return addOperands("=:=", operand1, operand2);
            case NOT_EQUALS:
                Collection<Pair<Term, ArrayList<Term>>> opUnion = new ArrayList<>(
                        addOperands(">", operand1, operand2));
                opUnion.addAll(addOperands("<", operand1, operand2));
                return opUnion;
            case LESS_THAN:
                return addOperands("<", operand1, operand2);
            case LESS_EQUAL:
                return addOperands("=<", operand1, operand2);
            case GREATER_THAN:
                return addOperands(">", operand1, operand2);
            case GREATER_EQUAL:
                return addOperands(">=", operand1, operand2);
            default:
                return null;
            }
        } else {
            return null;
        }
    }

    private static Collection<Pair<Term, ArrayList<Term>>> paramExpressionToCLP(String paramName, AExpression ce) {

        ArrayList<Term> vars = new ArrayList<>();

        Term paramVariable = CVar2PrologVar(paramName);
        vars.add(paramVariable);
        Term expTerm = null;

        if (ce instanceof CIdExpression) {
            vars.add(CVar2PrologVar(ce.toString()));
            expTerm = CVar2PrologVar(ce.toString());
            Term paramAexpTerm = new Compound("=:=", new Term[] { paramVariable, expTerm });
            return Collections.singleton(Pair.of(Util.termArrayToList(new Term[] { paramAexpTerm }), vars));
        } else if (ce instanceof CIntegerLiteralExpression) {
            expTerm = Util.textToTerm("rdiv(" + ce.toString() + ",1)");
            Term paramAexpTerm = new Compound("=:=", new Term[] { paramVariable, expTerm });
            return Collections.singleton(Pair.of(Util.termArrayToList(new Term[] { paramAexpTerm }), vars));
        } else if (ce instanceof CBinaryExpression) {
            CBinaryExpression bexp = (CBinaryExpression) ce;
            Collection<Pair<Term, ArrayList<Term>>> aexpTerms = expressionToCLP(ce);
            Collection<Pair<Term, ArrayList<Term>>> paramAexpTerms = new ArrayList<>(aexpTerms.size());
            switch (bexp.getOperator()) {
            case PLUS:
            case MINUS:
            case MULTIPLY:
            case DIVIDE:
                for (Pair<Term, ArrayList<Term>> aexpTerm : aexpTerms) {
                    ArrayList<Term> aexpTermVars = new ArrayList<>(aexpTerm.getSecond());
                    aexpTermVars.add(paramVariable);
                    Term paramAexpTerm = new Compound("=:=", new Term[] { paramVariable, aexpTerm.getFirst() });
                    paramAexpTerms.add(Pair.of(Util.termArrayToList(new Term[] { paramAexpTerm }), aexpTermVars));
                }
                return paramAexpTerms;
            // add an extra atomic constraint
            case EQUALS:
            case LESS_THAN:
            case LESS_EQUAL:
            case GREATER_THAN:
            case GREATER_EQUAL:
            case NOT_EQUALS:
                for (Pair<Term, ArrayList<Term>> aexpTerm : aexpTerms) {
                    ArrayList<Term> aexpTermVars = new ArrayList<>(aexpTerm.getSecond());
                    aexpTermVars.add(paramVariable);
                    Term paramAexpTerm = new Compound("=:=",
                            new Term[] { paramVariable, Util.textToTerm("rdiv(1,1)") });
                    paramAexpTerms.add(Pair.of(
                            Util.termArrayToList(new Term[] { paramAexpTerm, aexpTerm.getFirst() }), aexpTermVars));
                    paramAexpTerm = new Compound("=:=", new Term[] { paramVariable, Util.textToTerm("rdiv(0,1)") });
                    for (Pair<Term, ArrayList<Term>> negAexpTerm : getNegatedConstraintList(aexpTerm)) {
                        paramAexpTerms.add(
                                Pair.of(Util.termArrayToList(new Term[] { paramAexpTerm, negAexpTerm.getFirst() }),
                                        aexpTermVars));
                    }
                }
                return paramAexpTerms;
            default:
                return null;
            }
        } else {
            return null;
        }
    }

    private static Collection<Pair<Term, ArrayList<Term>>> addOperands(String operator,
            Collection<Pair<Term, ArrayList<Term>>> operand1, Collection<Pair<Term, ArrayList<Term>>> operand2) {

        Collection<Pair<Term, ArrayList<Term>>> termList = new ArrayList<>();
        ArrayList<Term> vars = new ArrayList<>();

        for (Pair<Term, ArrayList<Term>> subop1 : operand1) {
            for (Pair<Term, ArrayList<Term>> subop2 : operand2) {
                vars.addAll(subop1.getSecond());
                vars.addAll(subop2.getSecond());
                termList.add(Pair.of(
                        (Term) new Compound(operator, new Term[] { subop1.getFirst(), subop2.getFirst() }), vars));
            }
        }

        return termList;
    }

    private static boolean initFiringRelation(String firingRelation) {

        String qStr = "assert((less(C1,C2)";

        switch (firingRelation) {
        case "Always":
            break;
        case "Maxcoeff":
            qStr += ":-less_maxcoeff_cns(C1,C2)";
            break;
        case "Sumcoeff":
            qStr += ":-less_maxsum_cns(C1,C2)";
            break;
        case "Homeocoeff":
            qStr += ":-homeo_embedded_cns(C1,C2)";
            break;
        default:
            throw new AssertionError("Not valid value for the firing relation");
        }

        qStr += "))";

        Query q = new Query(qStr);

        return q.hasSolution();
    }

    private static boolean initGeneralizationOperator(String generalizationOperator) {

        String qStr = "assert((generalize(C1,C2,C3)";

        switch (generalizationOperator) {
        case "Top":
            break;
        case "Widen":
            qStr += ":-plain_cns_widening(C1,C2,C3)";
            break;
        case "WidenMax":
            qStr += ":-e_leq_maxcoeff(C1,C2,C3)";
            break;
        case "WidenSum":
            qStr += ":-e_leq_maxsum(C1,C2,C3)";
            break;
        default:
            throw new AssertionError("invalid value for the firing relation");
        }

        qStr += "))";

        Query q = new Query(qStr);

        return q.hasSolution();
    }

    /**
     * Compute over-approximation of convex hull of two constraints.
     * TODO: Currently the over-approximation is always very imprecise (it is just the top element)
     * @param cn1 the first constraint
     * @param cn2s the second constraint
     */
    public static Constraint convexHull(Constraint cn1, Constraint cn2s) {
        return new Constraint();
    }

    private ConstraintManager() {
    }

}