org.sosy_lab.cpachecker.util.ci.translators.ApronRequirementsTranslator.java Source code

Java tutorial

Introduction

Here is the source code for org.sosy_lab.cpachecker.util.ci.translators.ApronRequirementsTranslator.java

Source

/*
 *  CPAchecker is a tool for configurable software verification.
 *  This file is part of CPAchecker.
 *
 *  Copyright (C) 2007-2015  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.util.ci.translators;

import gmp.Mpfr;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.annotation.Nullable;

import org.sosy_lab.common.log.LogManager;
import org.sosy_lab.cpachecker.cpa.apron.ApronState;
import org.sosy_lab.cpachecker.util.Pair;
import org.sosy_lab.cpachecker.util.predicates.pathformula.SSAMap;
import org.sosy_lab.cpachecker.util.states.MemoryLocation;

import apron.Coeff;
import apron.DoubleScalar;
import apron.MpfrScalar;
import apron.MpqScalar;
import apron.Scalar;
import apron.Tcons0;
import apron.Texpr0BinNode;
import apron.Texpr0CstNode;
import apron.Texpr0DimNode;
import apron.Texpr0Node;
import apron.Texpr0UnNode;

import com.google.common.collect.Sets;
import com.google.common.math.DoubleMath;

public class ApronRequirementsTranslator extends CartesianRequirementsTranslator<ApronState> {

    private Pair<ApronState, Collection<String>> stateToRequiredVars;

    public ApronRequirementsTranslator(Class<ApronState> pAbstractStateClass, LogManager pLog) {
        super(pAbstractStateClass, pLog);
    }

    @Override
    protected List<String> getVarsInRequirements(ApronState pRequirement) {
        Collection<String> result = getConvexHullRequiredVars(pRequirement, null); // TODO
        stateToRequiredVars = Pair.of(pRequirement, result);
        return new ArrayList<>(result);
    }

    @Override
    protected List<String> getVarsInRequirements(final ApronState pRequirement,
            final @Nullable Collection<String> pRequiredVars) {
        Collection<String> result = getConvexHullRequiredVars(pRequirement, pRequiredVars);
        stateToRequiredVars = Pair.of(pRequirement, result);
        return new ArrayList<>(result);
    }

    @Override
    protected List<String> getListOfIndependentRequirements(ApronState pRequirement, SSAMap pIndices,
            final @Nullable Collection<String> pRequiredVars) {
        List<String> result = new ArrayList<>();
        List<String> varNames = getAllVarNames(pRequirement);
        Collection<String> requiredVarNames = null;

        if (stateToRequiredVars != null) {
            requiredVarNames = stateToRequiredVars.getSecond();
            if (stateToRequiredVars.getFirst() != pRequirement) {
                requiredVarNames = null;
            }
        }

        if (requiredVarNames == null) {
            requiredVarNames = getConvexHullRequiredVars(pRequirement, null); // TODO
        }

        String converted;
        for (Tcons0 constraint : pRequirement.getApronNativeState()
                .toTcons(pRequirement.getManager().getManager())) {
            converted = convertConstraintToFormula(constraint, varNames, pIndices, requiredVarNames);
            if (converted != null) {
                result.add(converted);
            }
        }

        return result;
    }

    private List<String> getAllVarNames(final ApronState pRequirement) {
        List<String> result = new ArrayList<>(pRequirement.getIntegerVariableToIndexMap().size()
                + pRequirement.getRealVariableToIndexMap().size());

        for (MemoryLocation mem : pRequirement.getIntegerVariableToIndexMap()) {
            result.add(mem.getAsSimpleString());
        }

        for (MemoryLocation mem : pRequirement.getRealVariableToIndexMap()) {
            result.add(mem.getAsSimpleString());
        }

        return result;
    }

    private Collection<String> getConvexHullRequiredVars(final ApronState pRequirement,
            final @Nullable Collection<String> requiredVars) {
        Set<String> seenRequired = new HashSet<>();
        Set<String> required;
        if (requiredVars == null) {
            required = new HashSet<>();
        } else {
            required = new HashSet<>(requiredVars);
        }
        List<String> varNames = getAllVarNames(pRequirement);
        Tcons0[] constraints = pRequirement.getApronNativeState().toTcons(pRequirement.getManager().getManager());
        List<Set<String>> constraintVars = new ArrayList<>(constraints.length);

        for (Tcons0 constraint : constraints) {
            constraintVars.add(getVarsInConstraint(constraint, varNames));
        }

        Iterator<Set<String>> it = constraintVars.iterator();

        int setSize;
        Set<String> intermediate;

        while (it.hasNext()) {
            intermediate = it.next();
            if (!Sets.intersection(required, intermediate).isEmpty()) {
                setSize = seenRequired.size();
                seenRequired.addAll(intermediate);
                required.addAll(intermediate);

                if (setSize != seenRequired.size()) {
                    it = constraintVars.iterator();
                }
            }
        }

        return seenRequired;
    }

    private Set<String> getVarsInConstraint(final Tcons0 constraint, final List<String> varNames) {
        Set<String> vars = Sets.newHashSetWithExpectedSize(constraint.getSize());

        Deque<Texpr0Node> stack = new ArrayDeque<>();
        stack.push(constraint.getExpression().toTexpr0Node());

        Texpr0Node current;
        while (!stack.isEmpty()) {
            current = stack.pop();

            if (current instanceof Texpr0BinNode) {
                stack.push(((Texpr0BinNode) current).getLeftArgument());
                stack.push(((Texpr0BinNode) current).getRightArgument());
            } else if (current instanceof Texpr0UnNode) {
                stack.push(((Texpr0UnNode) current).getArgument());
            } else if (current instanceof Texpr0DimNode) {
                vars.add(varNames.get(((Texpr0DimNode) current).dim));
            }
        }
        return vars;
    }

    private @Nullable String convertConstraintToFormula(final Tcons0 constraint, final List<String> varNames,
            final SSAMap map, final Collection<String> varsConsidered) {
        StringBuilder sb = new StringBuilder();
        sb.append("(");

        switch (constraint.kind) {
        case Tcons0.EQ:
            sb.append("=");
            break;
        case Tcons0.SUPEQ:
            sb.append(">=");
            break;
        case Tcons0.SUP:
            sb.append(">");
            break;
        case Tcons0.DISEQ:
            sb.append("not (=");
            break;
        case Tcons0.EQMOD:
            sb.append("= (mod");
            break;
        default:
            assert (false);
        }

        String left = convertLeftConstraintPartToFormula(varNames, map, varsConsidered);
        if (left == null) {
            return null;
        }

        sb.append(left);

        if (constraint.kind == Tcons0.EQMOD) {
            sb.append(" ");
            sb.append(getIntegerValFromScalar(constraint.getScalar()));
            sb.append(")");
        }

        sb.append(" 0)");

        if (constraint.kind == Tcons0.DISEQ) {
            sb.append(")");
        }

        return sb.toString();
    }

    private String getIntegerValFromScalar(final Scalar pCst) {
        double value;
        if (pCst instanceof DoubleScalar) {
            value = ((DoubleScalar) pCst).get();
        } else if (pCst instanceof MpfrScalar) {
            value = ((MpfrScalar) pCst).get().doubleValue(Mpfr.RNDN);
        } else {
            assert (pCst instanceof MpqScalar);
            value = ((MpqScalar) pCst).get().doubleValue();
        }
        if (DoubleMath.isMathematicalInteger(value)) {
            return String.valueOf((int) value);
        }
        throw new AssertionError("Cannot deal with this non-integer scalar");
    }

    private @Nullable String convertLeftConstraintPartToFormula(final List<String> varNames, final SSAMap map,
            final Collection<String> varsConsidered) {
        boolean toConsider = false;
        StringBuilder sb = new StringBuilder();

        Deque<Pair<Texpr0Node, Integer>> stack = new ArrayDeque<>();

        Pair<Texpr0Node, Integer> currentPair;
        Texpr0Node current;
        Coeff cst;
        String variableName;
        while (!stack.isEmpty()) {
            currentPair = stack.pop();
            current = currentPair.getFirst();

            if (current instanceof Texpr0BinNode) {
                sb.append(" (");

                switch (((Texpr0BinNode) current).getOperation()) {
                case Texpr0BinNode.OP_ADD:
                    sb.append("+");
                    break;
                case Texpr0BinNode.OP_SUB:
                    sb.append("-");
                    break;
                case Texpr0BinNode.OP_MUL:
                    sb.append("*");
                    break;
                case Texpr0BinNode.OP_DIV:
                    sb.append("/");
                    break;
                case Texpr0BinNode.OP_MOD:
                    sb.append("mod");
                    break;
                default:
                    throw new AssertionError("Unsupported binary operator.");
                }

                stack.push(Pair.of(((Texpr0BinNode) current).getLeftArgument(), 0));
                stack.push(Pair.of(((Texpr0BinNode) current).getRightArgument(), currentPair.getSecond() + 1));
            } else if (current instanceof Texpr0UnNode) {

                switch (((Texpr0UnNode) current).getOperation()) {
                case Texpr0UnNode.OP_NEG:
                    sb.append(" (-");
                    break;
                default:
                    throw new AssertionError("Unsupported unary operator.");
                }

                stack.push(Pair.of(((Texpr0UnNode) current).getArgument(), currentPair.getSecond() + 1));
            } else {
                if (current instanceof Texpr0DimNode) {
                    variableName = varNames.get(((Texpr0DimNode) current).dim);
                    if (varsConsidered.contains(variableName)) {
                        toConsider = true;
                    }
                    sb.append(" ");
                    sb.append(getVarWithIndex(variableName, map));
                } else if (current instanceof Texpr0CstNode) {
                    cst = ((Texpr0CstNode) current).getConstant();

                    if (cst.isScalar()) {
                        sb.append(" ");
                        sb.append(getIntegerValFromScalar((Scalar) cst));
                    }

                    throw new AssertionError("Cannot handle coefficient");
                }
                addClosingRoundBrackets(sb, currentPair.getSecond());
            }
        }
        return toConsider ? sb.toString() : null;
    }

    private void addClosingRoundBrackets(final StringBuilder sb, final int number) {
        for (int i = 0; i < number; i++) {
            sb.append(")");
        }
    }

}