edu.buaa.satla.analysis.core.predicate.PredicatePrecision.java Source code

Java tutorial

Introduction

Here is the source code for edu.buaa.satla.analysis.core.predicate.PredicatePrecision.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 edu.buaa.satla.analysis.core.predicate;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import org.sosy_lab.common.Pair;
import org.sosy_lab.cpachecker.cfa.model.CFANode;
import org.sosy_lab.cpachecker.core.interfaces.Precision;

import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;

import edu.buaa.satla.analysis.util.CFAUtils;
import edu.buaa.satla.analysis.util.UniqueIdGenerator;
import edu.buaa.satla.analysis.util.predicates.AbstractionPredicate;

/**
 * This class represents the precision of the PredicateCPA.
 * It is basically a map which assigns to each node in the CFA a (possibly empty)
 * set of predicates which should be used at this location.
 * Additionally, there may be some predicates which are used for all locations
 * ("global" predicates), and some predicates which are used for all locations
 * within a specific function.
 *
 * All instances of this class are immutable.
 */
public class PredicatePrecision implements Precision {

    // do not access theses sets directly except in their getters
    // (overrides from subclass need to be used)
    private final ImmutableSetMultimap<Pair<CFANode, Integer>, AbstractionPredicate> mLocationInstancePredicates;
    private final ImmutableSetMultimap<CFANode, AbstractionPredicate> mLocalPredicates;
    private final ImmutableSetMultimap<String, AbstractionPredicate> mFunctionPredicates;
    private final ImmutableSet<AbstractionPredicate> mGlobalPredicates;

    private static final UniqueIdGenerator idGenerator = new UniqueIdGenerator();
    private final int id = idGenerator.getFreshId();

    public PredicatePrecision(Multimap<Pair<CFANode, Integer>, AbstractionPredicate> pLocationInstancePredicates,
            Multimap<CFANode, AbstractionPredicate> pLocalPredicates,
            Multimap<String, AbstractionPredicate> pFunctionPredicates,
            Collection<AbstractionPredicate> pGlobalPredicates) {
        mLocationInstancePredicates = ImmutableSetMultimap.copyOf(pLocationInstancePredicates);
        mLocalPredicates = sortedImmutableSetCopyOf(pLocalPredicates);
        mFunctionPredicates = sortedImmutableSetCopyOf(pFunctionPredicates);
        mGlobalPredicates = ImmutableSet.copyOf(pGlobalPredicates);
    }

    private static <K extends Comparable<? super K>, V> ImmutableSetMultimap<K, V> sortedImmutableSetCopyOf(
            Multimap<K, V> m) {
        return ImmutableSetMultimap.<K, V>builder().orderKeysBy(Ordering.natural()).putAll(m).build();
    }

    /**
     * Create a new, empty precision.
     */
    public static PredicatePrecision empty() {
        return new PredicatePrecision(ImmutableSetMultimap.<Pair<CFANode, Integer>, AbstractionPredicate>of(),
                ImmutableSetMultimap.<CFANode, AbstractionPredicate>of(),
                ImmutableSetMultimap.<String, AbstractionPredicate>of(), ImmutableSet.<AbstractionPredicate>of());
    }

    /**
     * Return a table of the location-instance-specific predicates.
     * These are the predicates that should be used at the n-th instance
     * of an abstraction location l in the current path.
     */
    public ImmutableSetMultimap<Pair<CFANode, Integer>, AbstractionPredicate> getLocationInstancePredicates() {
        return mLocationInstancePredicates;
    }

    /**
     * Return a map view of the location-specific predicates of this precision.
     */
    public SetMultimap<CFANode, AbstractionPredicate> getLocalPredicates() {
        return mLocalPredicates;
    }

    /**
     * Return a map view of the function-specific predicates of this precision.
     */
    public SetMultimap<String, AbstractionPredicate> getFunctionPredicates() {
        return mFunctionPredicates;
    }

    /**
     * Return all global predicates in this precision.
     */
    public Set<AbstractionPredicate> getGlobalPredicates() {
        return mGlobalPredicates;
    }

    /**
     * Return all predicates for one specific location in this precision.
     * @param loc A CFA location.
     * @param locInstance How often this location has appeared in the current path.
     */
    public Set<AbstractionPredicate> getPredicates(CFANode loc, Integer locInstance) {
        Set<AbstractionPredicate> result = getLocationInstancePredicates().get(Pair.of(loc, locInstance));
        if (result.isEmpty()) {
            result = getLocalPredicates().get(loc);
        }
        if (result.isEmpty()) {
            result = getFunctionPredicates().get(loc.getFunctionName());
        }
        if (result.isEmpty()) {
            result = getGlobalPredicates();
        }
        return result;
    }

    /**
     * Create a new precision which is a copy of the current one with some
     * additional global predicates.
     */
    public PredicatePrecision addGlobalPredicates(Collection<AbstractionPredicate> newPredicates) {
        List<AbstractionPredicate> predicates = Lists.newArrayList(getGlobalPredicates());
        predicates.addAll(newPredicates);
        return new PredicatePrecision(getLocationInstancePredicates(), getLocalPredicates(),
                getFunctionPredicates(), predicates);
    }

    /**
     * Create a new precision which is a copy of the current one with some
     * additional function-specific predicates.
     */
    public PredicatePrecision addFunctionPredicates(Multimap<String, AbstractionPredicate> newPredicates) {
        Multimap<String, AbstractionPredicate> predicates = ArrayListMultimap.create(getFunctionPredicates());
        predicates.putAll(newPredicates);

        // During lookup, we do not look into getGlobalPredicates(),
        // if there is something for the key in predicates.
        // Thus, we copy the relevant items into the predicates set here.
        if (!getGlobalPredicates().isEmpty()) {
            for (String function : newPredicates.keySet()) {
                predicates.putAll(function, getGlobalPredicates());
            }
        }

        return new PredicatePrecision(getLocationInstancePredicates(), getLocalPredicates(), predicates,
                getGlobalPredicates());
    }

    /**
     * Create a new precision which is a copy of the current one with some
     * additional location-specific predicates.
     */
    public PredicatePrecision addLocalPredicates(Multimap<CFANode, AbstractionPredicate> newPredicates) {
        Multimap<CFANode, AbstractionPredicate> predicates = ArrayListMultimap.create(getLocalPredicates());
        predicates.putAll(newPredicates);

        // During lookup, we do not look into getGlobalPredicates() and getFunctionPredicates(),
        // if there is something for the key in predicates.
        // Thus, we copy the relevant items into the predicates set here.
        if (!getGlobalPredicates().isEmpty() || !getFunctionPredicates().isEmpty()) {
            for (CFANode newLoc : newPredicates.keySet()) {
                predicates.putAll(newLoc, getFunctionPredicates().get(newLoc.getFunctionName()));
                predicates.putAll(newLoc, getGlobalPredicates());
            }
        }

        return new PredicatePrecision(getLocationInstancePredicates(), predicates, getFunctionPredicates(),
                getGlobalPredicates());
    }

    /**
     * Create a new precision which is a copy of the current one with some
     * additional location-instance-specific predicates.
     */
    public PredicatePrecision addLocationInstancePredicates(
            Multimap<Pair<CFANode, Integer>, AbstractionPredicate> newPredicates) {
        Multimap<Pair<CFANode, Integer>, AbstractionPredicate> predicates = ArrayListMultimap
                .create(getLocationInstancePredicates());
        predicates.putAll(newPredicates);

        // During lookup, we do not look into getGlobalPredicates(),
        // getFunctionPredicates(), and getLocalPredicates(),
        // if there is something for the key in predicates.
        // Thus, we copy the relevant items into the predicates set here.
        if (!getGlobalPredicates().isEmpty() || !getFunctionPredicates().isEmpty()
                || !getLocalPredicates().isEmpty()) {
            for (Pair<CFANode, Integer> key : newPredicates.keySet()) {
                CFANode loc = key.getFirst();
                predicates.putAll(key, getLocalPredicates().get(loc));
                predicates.putAll(key, getFunctionPredicates().get(loc.getFunctionName()));
                predicates.putAll(key, getGlobalPredicates());
            }
        }

        return new PredicatePrecision(predicates, getLocalPredicates(), getFunctionPredicates(),
                getGlobalPredicates());
    }

    /**
     * Create a new precision which contains all predicates of this precision
     * and a second one.
     */
    public PredicatePrecision mergeWith(PredicatePrecision prec) {
        // create new set of global predicates
        Collection<AbstractionPredicate> newGlobalPredicates = Lists.newArrayList(getGlobalPredicates());
        newGlobalPredicates.addAll(prec.getGlobalPredicates());
        newGlobalPredicates = ImmutableSet.copyOf(newGlobalPredicates);

        // create new multimap of function-specific predicates
        Multimap<String, AbstractionPredicate> newFunctionPredicates = ArrayListMultimap
                .create(getFunctionPredicates());
        newFunctionPredicates.putAll(prec.getFunctionPredicates());

        if (!newGlobalPredicates.isEmpty()) {
            for (String function : newFunctionPredicates.keySet()) {
                newFunctionPredicates.putAll(function, newGlobalPredicates);
            }
        }
        newFunctionPredicates = ImmutableSetMultimap.copyOf(newFunctionPredicates);

        // create new multimap of location-specific predicates
        Multimap<CFANode, AbstractionPredicate> newLocalPredicates = ArrayListMultimap.create(getLocalPredicates());
        newLocalPredicates.putAll(prec.getLocalPredicates());

        if (!newGlobalPredicates.isEmpty() || !newFunctionPredicates.isEmpty()) {
            for (CFANode loc : newLocalPredicates.keySet()) {
                newLocalPredicates.putAll(loc, newGlobalPredicates);
                newLocalPredicates.putAll(loc, newFunctionPredicates.get(loc.getFunctionName()));
            }
        }

        // create new multimap of location-instance-specific predicates
        Multimap<Pair<CFANode, Integer>, AbstractionPredicate> newLocationInstanceSpecificPredicates = ArrayListMultimap
                .create(getLocationInstancePredicates());
        newLocationInstanceSpecificPredicates.putAll(prec.getLocationInstancePredicates());

        if (!newGlobalPredicates.isEmpty() || !newFunctionPredicates.isEmpty() || !newLocalPredicates.isEmpty()) {
            for (Pair<CFANode, Integer> key : newLocationInstanceSpecificPredicates.keySet()) {
                newLocationInstanceSpecificPredicates.putAll(key, newGlobalPredicates);
                newLocationInstanceSpecificPredicates.putAll(key,
                        newFunctionPredicates.get(key.getFirst().getFunctionName()));
                newLocationInstanceSpecificPredicates.putAll(key, newLocalPredicates.get(key.getFirst()));
            }
        }

        return new PredicatePrecision(newLocationInstanceSpecificPredicates, newLocalPredicates,
                newFunctionPredicates, newGlobalPredicates);
    }

    /**
     * Calculates a "difference" from this precision to another precision.
     * The difference is the number of predicates which are present in this precision,
     * and are missing in the other precision.
     * If a predicate is present in both precisions, but for different locations,
     * this counts as a difference.
     *
     * Note that this difference is not symmetric!
     * (Similar to {@link Sets#difference(Set, Set)}).
     */
    public int calculateDifferenceTo(PredicatePrecision other) {
        int difference = 0;
        difference += Sets.difference(this.getGlobalPredicates(), other.getGlobalPredicates()).size();

        difference += Sets
                .difference(this.getFunctionPredicates().entries(), other.getFunctionPredicates().entries()).size();

        difference += Sets.difference(this.getLocalPredicates().entries(), other.getLocalPredicates().entries())
                .size();

        difference += Sets.difference(this.getLocationInstancePredicates().entries(),
                other.getLocationInstancePredicates().entries()).size();
        return difference;
    }

    @Override
    public int hashCode() {
        return Objects.hash(getGlobalPredicates(), getFunctionPredicates(), getLocalPredicates(),
                getLocationInstancePredicates());
    }

    @Override
    public boolean equals(Object pObj) {
        if (pObj == this) {
            return true;
        } else if (pObj == null) {
            return false;
        } else if (!(pObj.getClass().equals(this.getClass()))) {
            return false;
        } else {
            PredicatePrecision other = (PredicatePrecision) pObj;
            return getLocationInstancePredicates().equals(other.getLocationInstancePredicates())
                    && getLocalPredicates().equals(other.getLocalPredicates())
                    && getFunctionPredicates().equals(other.getFunctionPredicates())
                    && getGlobalPredicates().equals(other.getGlobalPredicates());
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        if (!getGlobalPredicates().isEmpty()) {
            sb.append("global predicates: ");
            sb.append(getGlobalPredicates());
        }
        if (!getFunctionPredicates().isEmpty()) {
            if (sb.length() > 0) {
                sb.append(", ");
            }
            sb.append("function predicates: ");
            sb.append(getFunctionPredicates());
        }
        if (!getLocalPredicates().isEmpty()) {
            if (sb.length() > 0) {
                sb.append(", ");
            }
            sb.append("local predicates: ");
            sb.append(getLocalPredicates());
        }
        if (!getLocationInstancePredicates().isEmpty()) {
            if (sb.length() > 0) {
                sb.append(", ");
            }
            sb.append("location-instance predicates: ");
            sb.append(getLocationInstancePredicates());
        }

        if (sb.length() == 0) {
            return "empty";
        } else {
            return sb.toString();
        }
    }

    /**
     * Get the unique id of this precision object.
     */
    public int getId() {
        return id;
    }

    static ListMultimap<String, AbstractionPredicate> mergePredicatesPerFunction(
            Multimap<Pair<CFANode, Integer>, AbstractionPredicate> newPredicates) {

        return transformAndMergeKeys(newPredicates,
                Functions.compose(CFAUtils.GET_FUNCTION, Pair.<CFANode>getProjectionToFirst()));
    }

    static ListMultimap<CFANode, AbstractionPredicate> mergePredicatesPerLocation(
            Multimap<Pair<CFANode, Integer>, AbstractionPredicate> newPredicates) {

        return transformAndMergeKeys(newPredicates, Pair.<CFANode>getProjectionToFirst());
    }

    private static <K1, K2, V> ListMultimap<K2, V> transformAndMergeKeys(Multimap<K1, V> input,
            Function<? super K1, K2> transformFunction) {

        ListMultimap<K2, V> result = ArrayListMultimap.create();
        for (Map.Entry<K1, Collection<V>> entry : input.asMap().entrySet()) {
            result.putAll(transformFunction.apply(entry.getKey()), entry.getValue());
        }
        return result;
    }
}