org.sosy_lab.cpachecker.util.templates.Template.java Source code

Java tutorial

Introduction

Here is the source code for org.sosy_lab.cpachecker.util.templates.Template.java

Source

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

import com.google.common.collect.Iterables;

import org.sosy_lab.common.rationals.LinearExpression;
import org.sosy_lab.common.rationals.Rational;
import org.sosy_lab.cpachecker.cfa.ast.c.CIdExpression;
import org.sosy_lab.cpachecker.cfa.types.c.CSimpleType;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.stream.Stream;

/**
 * Linear expression over program variables.
 */
public class Template {
    // todo: switch to MemoryLocation, additionally track type.
    private final LinearExpression<CIdExpression> linearExpression;

    public Stream<String> getUsedVars() {
        return linearExpression.getMap().keySet().stream().map(s -> s.getDeclaration().getQualifiedName());
    }

    public boolean hasGlobals() {
        return getUsedVars().filter(s -> !s.contains("::")).findAny().isPresent();
    }

    /**
     * Template type.
     */
    public enum Kind {
        // Intervals.
        UPPER_BOUND, // +x
        NEG_LOWER_BOUND, // -x

        // Octagons.
        SUM, // +x+y
        DIFFERENCE, //x-y
        NEG_SUM_LOWER_BOUND, //-x-y

        // Everything else.
        COMPLEX
    }

    private Template(LinearExpression<CIdExpression> pLinearExpression) {
        linearExpression = pLinearExpression;
    }

    public Kind getKind() {
        return getKind(linearExpression);
    }

    public LinearExpression<CIdExpression> getLinearExpression() {
        return linearExpression;
    }

    public boolean isUnsigned() {
        for (Entry<CIdExpression, Rational> e : linearExpression) {
            CIdExpression expr = e.getKey();
            CSimpleType type = (CSimpleType) expr.getExpressionType();
            if (!type.isUnsigned()) {
                return false;
            }
        }
        return true;
    }

    public boolean isIntegral() {
        for (Entry<CIdExpression, Rational> e : linearExpression) {
            Rational coeff = e.getValue();
            CIdExpression id = e.getKey();
            if (!(coeff.isIntegral() && ((CSimpleType) id.getExpressionType()).getType().isIntegerType())) {
                return false;
            }
        }
        return true;
    }

    public static Template of(LinearExpression<CIdExpression> expr) {
        return new Template(expr);
    }

    private static Kind getKind(LinearExpression<CIdExpression> expr) {
        int s = expr.size();
        if (s == 1 && Objects.equals(Iterables.getOnlyElement(expr).getValue(), Rational.ONE)) {

            return Kind.UPPER_BOUND;
        } else if (s == 1 && Objects.equals(Iterables.getOnlyElement(expr).getValue(), Rational.NEG_ONE)) {

            return Kind.NEG_LOWER_BOUND;
        } else if (s == 2) {
            Iterator<Entry<CIdExpression, Rational>> it = expr.iterator();
            Rational a = it.next().getValue();
            Rational b = it.next().getValue();
            if (Objects.equals(a, Rational.ONE) && Objects.equals(b, Rational.ONE)) {
                return Kind.SUM;
            } else if (Objects.equals(a, Rational.NEG_ONE) && Objects.equals(b, Rational.NEG_ONE)) {
                return Kind.NEG_SUM_LOWER_BOUND;
            } else if ((Objects.equals(a, Rational.ONE) && Objects.equals(b, Rational.NEG_ONE))
                    || (Objects.equals(a, Rational.NEG_ONE) && Objects.equals(b, Rational.ONE))) {
                return Kind.DIFFERENCE;
            }
        }
        return Kind.COMPLEX;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null) {
            return false;
        }
        if (o.getClass() != this.getClass()) {
            return false;
        }
        Template other = (Template) o;
        return linearExpression.equals(other.linearExpression);
    }

    @Override
    public int hashCode() {
        return linearExpression.hashCode();
    }

    public int size() {
        return linearExpression.size();
    }

    /**
     * @return String suitable for formula serialization.
     * Guarantees that two equal templates will get an equal serialization.
     */
    @Override
    public String toString() {

        // Sort by .getQualifiedName() first.
        Map<String, CIdExpression> mapping = new HashMap<>();
        ArrayList<String> varNames = new ArrayList<>();

        for (Entry<CIdExpression, Rational> monomial : linearExpression) {
            CIdExpression key = monomial.getKey();
            String varName = key.getDeclaration().getQualifiedName();

            mapping.put(varName, key);
            varNames.add(varName);
        }

        Collections.sort(varNames);

        StringBuilder b = new StringBuilder();
        for (String varName : varNames) {
            Rational coeff = linearExpression.getCoeff(mapping.get(varName));

            LinearExpression.writeMonomial(varName, coeff, b);
        }
        return b.toString();
    }
}