org.sosy_lab.cpachecker.cpa.bdd.BDDCompressExpressionVisitor.java Source code

Java tutorial

Introduction

Here is the source code for org.sosy_lab.cpachecker.cpa.bdd.BDDCompressExpressionVisitor.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.bdd;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;

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.CCastExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CCharLiteralExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CIdExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.CIntegerLiteralExpression;
import org.sosy_lab.cpachecker.cfa.ast.c.DefaultCExpressionVisitor;
import org.sosy_lab.cpachecker.cfa.model.CFANode;
import org.sosy_lab.cpachecker.cfa.types.c.CEnumType.CEnumerator;
import org.sosy_lab.cpachecker.core.defaults.VariableTrackingPrecision;
import org.sosy_lab.cpachecker.util.VariableClassification.Partition;
import org.sosy_lab.cpachecker.util.VariableClassificationBuilder;
import org.sosy_lab.cpachecker.util.predicates.interfaces.Region;

import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;

/**
 * This Visitor implements evaluation of expressions,
 * that contain only checks for equality of numbers.
 * In this special case it is possible to store the information in less bits than 32.
 */
public class BDDCompressExpressionVisitor extends DefaultCExpressionVisitor<Region[], RuntimeException> {

    /** This map contains tuples (int, region[]) for each intEqual-partition. */
    private static final Map<Partition, Map<BigInteger, Region[]>> INT_REGIONS_MAP = new HashMap<>();

    private final PredicateManager predMgr;
    private final VariableTrackingPrecision precision;
    private final BitvectorManager bvmgr;
    private final Map<BigInteger, Region[]> intToRegions;
    private final int size;
    private final CFANode location;

    /** This Visitor returns a representation for an expression.
     * @param size length of compressed bitvector
     * @param pPartition info about variables and numbers
     */
    public BDDCompressExpressionVisitor(final PredicateManager pPredMgr, final VariableTrackingPrecision pPrecision,
            final int size, final CFANode pLocation, final BitvectorManager pBVmgr, final Partition pPartition) {
        Preconditions.checkNotNull(pPartition);
        this.predMgr = pPredMgr;
        this.precision = pPrecision;
        this.bvmgr = pBVmgr;
        this.size = size;
        this.intToRegions = initMappingIntToRegions(pPartition);
        this.location = pLocation;
    }

    /** This function creates a mapping of intEqual partitions to a mapping of number to bitvector.
     * This allows to compress big numbers to a small number of bits in the BDD. */
    private Map<BigInteger, Region[]> initMappingIntToRegions(final Partition partition) {

        if (!INT_REGIONS_MAP.containsKey(partition)) {
            final Map<BigInteger, Region[]> currentMapping = new HashMap<>();

            // special handling of One and Zero,
            // because they can appear as result of an equality-check.
            // this allows us to check expressions as "((a==0)==5)" with varClass intEQ
            currentMapping.put(BigInteger.ZERO, bvmgr.makeNumber(BigInteger.valueOf(0), size));
            currentMapping.put(BigInteger.ONE, bvmgr.makeNumber(BigInteger.valueOf(1), size));

            int i = 2;
            for (BigInteger num : Sets.difference(partition.getValues(),
                    Sets.newHashSet(BigInteger.ZERO, BigInteger.ONE))) {
                currentMapping.put(num, bvmgr.makeNumber(BigInteger.valueOf(i), size));
                i++;
            }
            INT_REGIONS_MAP.put(partition, currentMapping);
        }
        return INT_REGIONS_MAP.get(partition);
    }

    @Override
    protected Region[] visitDefault(CExpression pExp) {
        return null;
    }

    @Override
    public Region[] visit(final CBinaryExpression pE) {

        // for numeral values
        Region[] lVal;
        BigInteger val1 = VariableClassificationBuilder.getNumber(pE.getOperand1());
        if (val1 == null) {
            lVal = pE.getOperand1().accept(this);
        } else {
            lVal = intToRegions.get(val1);
            assert lVal != null;
        }

        // for numeral values
        BigInteger val2 = VariableClassificationBuilder.getNumber(pE.getOperand2());
        Region[] rVal;
        if (val2 == null) {
            rVal = pE.getOperand2().accept(this);
        } else {
            rVal = intToRegions.get(val2);
            assert rVal != null;
        }

        if (lVal == null || rVal == null) {
            return null;
        }

        return calculateBinaryOperation(lVal, rVal, bvmgr, pE);
    }

    private static Region[] calculateBinaryOperation(Region[] lVal, Region[] rVal, final BitvectorManager bvmgr,
            final CBinaryExpression binaryExpr) {

        assert lVal.length == rVal.length;
        final BinaryOperator binaryOperator = binaryExpr.getOperator();
        switch (binaryOperator) {
        case EQUALS:
            return bvmgr.wrapLast(bvmgr.makeLogicalEqual(lVal, rVal), lVal.length);
        case NOT_EQUALS:
            return bvmgr.wrapLast(bvmgr.makeNot(bvmgr.makeLogicalEqual(lVal, rVal)), lVal.length);
        default:
            throw new AssertionError("no support for further operators: " + binaryOperator);
        }
    }

    @Override
    public Region[] visit(CCharLiteralExpression pE) {
        return intToRegions.get(BigInteger.valueOf(pE.getCharacter()));
    }

    @Override
    public Region[] visit(CIntegerLiteralExpression pE) {
        return intToRegions.get(pE.getValue());
    }

    @Override
    public Region[] visit(CIdExpression idExp) {
        if (idExp.getDeclaration() instanceof CEnumerator) {
            CEnumerator enumerator = (CEnumerator) idExp.getDeclaration();
            if (enumerator.hasValue()) {
                return intToRegions.get(BigInteger.valueOf(enumerator.getValue()));
            } else {
                return null;
            }
        }
        return predMgr.createPredicate(idExp.getDeclaration().getQualifiedName(), idExp.getExpressionType(),
                location, size, precision);
    }

    @Override
    public Region[] visit(final CCastExpression castExpression) {
        // We do not expect a changing value through a cast, because then this code would be unsound!
        // This assumption might be unrealistic, but it works in many cases.
        // This code also matches the code in VariableClassification, line 1413, where casts are ignored for intEQ.
        return castExpression.getOperand().accept(this);
    }
}