org.sosy_lab.cpachecker.cpa.predicate.persistence.PredicateAbstractionsStorage.java Source code

Java tutorial

Introduction

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

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.regex.Pattern;

import org.sosy_lab.common.Pair;
import org.sosy_lab.common.configuration.InvalidConfigurationException;
import org.sosy_lab.common.io.Files;
import org.sosy_lab.common.io.Path;
import org.sosy_lab.common.log.LogManager;
import org.sosy_lab.cpachecker.cpa.predicate.persistence.PredicatePersistenceUtils.PredicateParsingFailedException;
import org.sosy_lab.cpachecker.util.predicates.interfaces.BooleanFormula;
import org.sosy_lab.cpachecker.util.predicates.interfaces.view.FormulaManagerView;

import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;

public class PredicateAbstractionsStorage {

    public static class AbstractionNode {
        private final int id;
        private final Optional<Integer> locationId;
        private final BooleanFormula formula;

        public AbstractionNode(int pId, BooleanFormula pFormula, Optional<Integer> pLocationId) {
            this.id = pId;
            this.formula = pFormula;
            this.locationId = pLocationId;
        }

        public BooleanFormula getFormula() {
            return formula;
        }

        public int getId() {
            return id;
        }

        public Optional<Integer> getLocationId() {
            return locationId;
        }

        @Override
        public String toString() {
            return Integer.toString(getId());
        }

        @Override
        public int hashCode() {
            // TODO
            return super.hashCode();
        }
    }

    private static final Pattern NODE_DECLARATION_PATTERN = Pattern
            .compile("^[0-9]+[ ]*\\(([0-9]+[,]*)*\\)[ ]*(@[0-9]+)$");

    private enum AbstractionsParserState {
        EXPECT_OF_COMMON_DEFINITIONS, EXPECT_NODE_DECLARATION, EXPECT_NODE_ABSTRACTION
    }

    private final Path abstractionsFile;
    private final FormulaManagerView fmgr;
    protected final LogManager logger;

    private Integer rootAbstractionId = null;
    private ImmutableMap<Integer, AbstractionNode> abstractions = ImmutableMap.of();
    private ImmutableMultimap<Integer, Integer> abstractionTree = ImmutableMultimap.of();
    private Set<Integer> reusedAbstractions = Sets.newTreeSet();

    public PredicateAbstractionsStorage(Path pFile, LogManager pLogger, FormulaManagerView pFmgr)
            throws PredicateParsingFailedException, InvalidConfigurationException {
        this.fmgr = pFmgr;
        this.logger = pLogger;
        this.abstractionsFile = pFile;

        if (pFile != null) {
            try {
                Files.checkReadableFile(pFile);
                parseAbstractionTree();
            } catch (IOException e) {
                throw new PredicateParsingFailedException(e, "Init", 0);
            }
        }
    }

    private void parseAbstractionTree() throws IOException, PredicateParsingFailedException {
        Multimap<Integer, Integer> resultTree = LinkedHashMultimap.create();
        Map<Integer, AbstractionNode> resultAbstractions = Maps.newTreeMap();
        Set<Integer> abstractionsWithParents = Sets.newTreeSet();

        String source = abstractionsFile.getName();
        try (BufferedReader reader = abstractionsFile.asCharSource(StandardCharsets.US_ASCII)
                .openBufferedStream()) {

            // first, read first section with initial set of function definitions
            Pair<Integer, String> defParsingResult = PredicatePersistenceUtils.parseCommonDefinitions(reader,
                    abstractionsFile.toString());
            int lineNo = defParsingResult.getFirst();
            String commonDefinitions = defParsingResult.getSecond();

            String currentLine;
            int currentAbstractionId = -1;
            Optional<Integer> currentLocationId = Optional.absent();
            Set<Integer> currentSuccessors = Sets.newTreeSet();

            AbstractionsParserState parserState = AbstractionsParserState.EXPECT_NODE_DECLARATION;
            while ((currentLine = reader.readLine()) != null) {
                lineNo++;
                currentLine = currentLine.trim();

                if (currentLine.isEmpty()) {
                    // blank lines separates sections
                    continue;
                }

                if (currentLine.startsWith("//")) {
                    // comment
                    continue;
                }

                if (parserState == AbstractionsParserState.EXPECT_NODE_DECLARATION) {
                    // we expect a new section header
                    if (!currentLine.endsWith(":")) {
                        throw new PredicateParsingFailedException(
                                currentLine + " is not a valid abstraction header", source, lineNo);
                    }

                    currentLine = currentLine.substring(0, currentLine.length() - 1).trim(); // strip off ":"
                    if (currentLine.isEmpty()) {
                        throw new PredicateParsingFailedException("empty header is not allowed", source, lineNo);
                    }

                    if (!NODE_DECLARATION_PATTERN.matcher(currentLine).matches()) {
                        throw new PredicateParsingFailedException(
                                currentLine + " is not a valid abstraction header", source, lineNo);
                    }

                    currentLocationId = null;
                    StringTokenizer declarationTokenizer = new StringTokenizer(currentLine, " (,):");
                    currentAbstractionId = Integer.parseInt(declarationTokenizer.nextToken());
                    while (declarationTokenizer.hasMoreTokens()) {
                        String token = declarationTokenizer.nextToken().trim();
                        if (token.length() > 0) {
                            if (token.startsWith("@")) {
                                currentLocationId = Optional.of(Integer.parseInt(token.substring(1)));
                            } else {
                                int successorId = Integer.parseInt(token);
                                currentSuccessors.add(successorId);
                            }
                        }
                    }

                    parserState = AbstractionsParserState.EXPECT_NODE_ABSTRACTION;

                } else if (parserState == AbstractionsParserState.EXPECT_NODE_ABSTRACTION) {
                    if (!currentLine.startsWith("(assert ") && currentLine.endsWith(")")) {
                        throw new PredicateParsingFailedException("unexpected line " + currentLine, source, lineNo);
                    }

                    BooleanFormula f;
                    try {
                        f = fmgr.parse(commonDefinitions + currentLine);
                    } catch (IllegalArgumentException e) {
                        throw new PredicateParsingFailedException(e, "Formula parsing", lineNo);
                    }

                    AbstractionNode abstractionNode = new AbstractionNode(currentAbstractionId, f,
                            currentLocationId);
                    resultAbstractions.put(currentAbstractionId, abstractionNode);
                    resultTree.putAll(currentAbstractionId, currentSuccessors);
                    abstractionsWithParents.addAll(currentSuccessors);
                    currentAbstractionId = -1;
                    currentSuccessors.clear();

                    parserState = AbstractionsParserState.EXPECT_NODE_DECLARATION;
                }
            }
        }

        // Determine root node
        Set<Integer> nodesWithNoParents = Sets.difference(resultAbstractions.keySet(), abstractionsWithParents);
        assert nodesWithNoParents.size() <= 1;
        if (!nodesWithNoParents.isEmpty()) {
            this.rootAbstractionId = nodesWithNoParents.iterator().next();
        } else {
            this.rootAbstractionId = null;
        }

        // Set results
        this.abstractions = ImmutableMap.copyOf(resultAbstractions);
        this.abstractionTree = ImmutableMultimap.copyOf(resultTree);
    }

    public AbstractionNode getAbstractionNode(int abstractionId) {
        return abstractions.get(abstractionId);
    }

    public ImmutableMultimap<Integer, Integer> getAbstractionTree() {
        return abstractionTree;
    }

    public Integer getRootAbstractionId() {
        return rootAbstractionId;
    }

    public Set<AbstractionNode> getSuccessorAbstractions(Integer ofAbstractionWithId) {
        Set<AbstractionNode> result = Sets.newHashSet();

        if (abstractionTree != null) {
            for (Integer successorId : abstractionTree.get(ofAbstractionWithId)) {
                if (successorId == null) {
                    continue;
                }
                AbstractionNode successor = abstractions.get(successorId);
                if (successor != null) {
                    result.add(successor);
                }
            }
        }

        return result;
    }

    public void markAbstractionBeingReused(Integer abstractionId) {
        Preconditions.checkNotNull(abstractionId);
        reusedAbstractions.add(abstractionId);
    }

    public boolean wasAbstractionReused(Integer abstractionId) {
        Preconditions.checkNotNull(abstractionId);
        return reusedAbstractions.contains(abstractionId);
    }

    public ImmutableMap<Integer, AbstractionNode> getAbstractions() {
        return abstractions;
    }

}