org.sosy_lab.cpachecker.cpa.automaton.Automaton.java Source code

Java tutorial

Introduction

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

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;

import org.sosy_lab.common.configuration.InvalidConfigurationException;

import com.google.common.collect.Maps;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

@SuppressFBWarnings(value = "VA_FORMAT_STRING_USES_NEWLINE", justification = "consistent Unix-style line endings")
public class Automaton {
    private final String name;
    /* The internal variables used by the actions/ assignments of this automaton.
     * This reference of the Map is unused because the actions/assignments get their reference from the parser.
     */
    private final Map<String, AutomatonVariable> initVars;
    private final List<AutomatonInternalState> states;
    private final AutomatonInternalState initState;

    public Automaton(String pName, Map<String, AutomatonVariable> pVars, List<AutomatonInternalState> pStates,
            String pInitialStateName) throws InvalidAutomatonException {
        this.name = pName;
        this.initVars = pVars;
        this.states = pStates;

        Map<String, AutomatonInternalState> statesMap = Maps.newHashMapWithExpectedSize(pStates.size());
        for (AutomatonInternalState s : pStates) {
            if (statesMap.put(s.getName(), s) != null) {
                throw new InvalidAutomatonException("State " + s.getName() + " exists twice in automaton " + pName);
            }
        }

        initState = statesMap.get(pInitialStateName);
        if (initState == null) {
            throw new InvalidAutomatonException(
                    "Inital state " + pInitialStateName + " not found in automaton " + pName);
        }

        // set the FollowStates of all Transitions
        for (AutomatonInternalState s : pStates) {
            s.setFollowStates(statesMap);
        }
    }

    public List<AutomatonInternalState> getStates() {
        return states;
    }

    public String getName() {
        return name;
    }

    AutomatonInternalState getInitialState() {
        return initState;
    }

    public int getNumberOfStates() {
        return states.size();
    }

    /**
     * Prints the contents of a DOT file representing this automaton to the PrintStream.
     * @param pOut
     * @throws IOException
     */
    void writeDotFile(Appendable pOut) throws IOException {
        pOut.append("digraph " + name + "{\n");

        boolean errorState = false;
        boolean bottomState = false;

        for (AutomatonInternalState s : states) {
            String color = initState.equals(s) ? "green" : "black";

            pOut.append(formatState(s, color));

            for (AutomatonTransition t : s.getTransitions()) {
                pOut.append(formatTransition(s, t));

                errorState = errorState || t.getFollowState().equals(AutomatonInternalState.ERROR);
                bottomState = bottomState || t.getFollowState().equals(AutomatonInternalState.BOTTOM);
            }
        }

        if (errorState) {
            pOut.append(formatState(AutomatonInternalState.ERROR, "red"));
        }

        if (bottomState) {
            pOut.append(formatState(AutomatonInternalState.BOTTOM, "red"));
        }
        pOut.append("}\n");
    }

    private static String formatState(AutomatonInternalState s, String color) {
        String name = s.getName().replace("_predefinedState_", "");
        String shape = s.getDoesMatchAll() ? "doublecircle" : "circle";
        return String.format("%d [shape=\"" + shape + "\" color=\"%s\" label=\"%s\"]\n", s.getStateId(), color,
                name);
    }

    private static String formatTransition(AutomatonInternalState sourceState, AutomatonTransition t) {
        return String.format("%d -> %d [label=\"%s\"]\n", sourceState.getStateId(), t.getFollowState().getStateId(),
                t.toString().replaceAll("\"", Matcher.quoteReplacement("\\\"")));
    }

    public Map<String, AutomatonVariable> getInitialVariables() {
        return initVars;
    }

    /**
     * Assert this automaton fulfills the requirements of an ObserverAutomaton.
     * This means the Automaton does not modify other CPAs (Keyword MODIFY) and does not use the BOTTOM element (Keyword STOP).
     * @throws InvalidConfigurationException if the requirements are not fulfilled
     */
    public void assertObserverAutomaton() throws InvalidConfigurationException {
        for (AutomatonInternalState s : this.states) {
            for (AutomatonTransition t : s.getTransitions()) {
                if (!t.meetsObserverRequirements()) {
                    throw new InvalidConfigurationException("The transition " + t + " in state \"" + s
                            + "\" is not valid for an ObserverAutomaton.");
                }
            }
        }
    }
}