edu.buaa.satla.analysis.core.arg.ARGToDotWriter.java Source code

Java tutorial

Introduction

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

import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.sosy_lab.common.Pair;
import org.sosy_lab.cpachecker.cfa.model.CFAEdge;
import org.sosy_lab.cpachecker.cfa.model.CFANode;
import org.sosy_lab.cpachecker.cfa.model.FunctionEntryNode;
import org.sosy_lab.cpachecker.cfa.model.FunctionExitNode;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Multimap;

import edu.buaa.satla.analysis.util.AbstractStates;

public class ARGToDotWriter {

    private final Appendable sb;

    ARGToDotWriter(Appendable pSb) throws IOException {
        sb = pSb;

        sb.append("digraph ARG {\n");
        // default style for nodes
        sb.append("node [style=\"filled\" shape=\"box\" color=\"white\"]\n");
    }

    /**
     * Create String with ARG in the DOT format of Graphviz.
     * @param sb Where to write the ARG into.
     * @param rootState the root element of the ARG
     * @param successorFunction A function giving all successors of an ARGState. Only states reachable from root by iteratively applying this function will be dumped.
     * @param displayedElements A predicate for selecting states that should be displayed. States which are only reachable via non-displayed states are ignored, too.
     * @param highlightEdge Which edges to highlight in the graph?
     * @throws IOException
     */
    public static void write(Appendable sb, final ARGState rootState,
            final Function<? super ARGState, ? extends Iterable<ARGState>> successorFunction,
            final Predicate<? super ARGState> displayedElements,
            final Predicate<? super Pair<ARGState, ARGState>> highlightEdge) throws IOException {

        ARGToDotWriter toDotWriter = new ARGToDotWriter(sb);
        toDotWriter.writeSubgraph(rootState, successorFunction, displayedElements, highlightEdge);
        toDotWriter.finish();
    }

    /**
     * Create String with ARG in the DOT format of Graphviz.
     * @param sb Where to write the ARG into.
     * @param rootStates the root elements of the ARGs
     * @param connections start- and end-points of edges between separate graphs
     * @param successorFunction A function giving all successors of an ARGState. Only states reachable from root by iteratively applying this function will be dumped.
     * @param displayedElements A predicate for selecting states that should be displayed. States which are only reachable via non-displayed states are ignored, too.
     * @param highlightEdge Which edges to highlight in the graph?
     * @throws IOException
     */
    public static void write(final Appendable sb, final Set<ARGState> rootStates,
            final Multimap<ARGState, ARGState> connections,
            final Function<? super ARGState, ? extends Iterable<ARGState>> successorFunction,
            final Predicate<? super ARGState> displayedElements,
            final Predicate<? super Pair<ARGState, ARGState>> highlightEdge) throws IOException {

        ARGToDotWriter toDotWriter = new ARGToDotWriter(sb);
        for (ARGState rootState : rootStates) {
            toDotWriter.enterSubgraph("cluster_" + rootState.getStateId(), "reachedset_" + rootState.getStateId());
            toDotWriter.writeSubgraph(rootState, successorFunction, displayedElements, highlightEdge);
            toDotWriter.leaveSubgraph();
        }

        for (Map.Entry<ARGState, ARGState> connection : connections.entries()) {
            sb.append(connection.getKey().getStateId() + " -> " + connection.getValue().getStateId());
            sb.append(" [color=green style=bold]\n");
        }

        toDotWriter.finish();
    }

    /**
     * Create String with ARG in the DOT format of Graphviz.
     * Only the states and edges are written, no surrounding graph definition.
     * @param sb Where to write the ARG into.
     * @param rootState the root element of the ARG
     * @param successorFunction A function giving all successors of an ARGState. Only states reachable from root by iteratively applying this function will be dumped.
     * @param displayedElements A predicate for selecting states that should be displayed. States which are only reachable via non-displayed states are ignored, too.
     * @param highlightEdge Which edges to highlight in the graph?
     * @throws IOException
     */
    void writeSubgraph(final ARGState rootState,
            final Function<? super ARGState, ? extends Iterable<ARGState>> successorFunction,
            final Predicate<? super ARGState> displayedElements,
            final Predicate<? super Pair<ARGState, ARGState>> highlightEdge) throws IOException {

        Deque<ARGState> worklist = new ArrayDeque<>();
        Set<ARGState> processed = new HashSet<>();
        StringBuilder edges = new StringBuilder();

        worklist.add(rootState);

        while (!worklist.isEmpty()) {
            ARGState currentElement = worklist.removeLast();
            if (!displayedElements.apply(currentElement)) {
                continue;
            }
            if (!processed.add(currentElement)) {
                continue;
            }

            sb.append(determineNode(currentElement));
            sb.append(determineStateHint(currentElement));

            for (ARGState covered : currentElement.getCoveredByThis()) {
                edges.append(covered.getStateId());
                edges.append(" -> ");
                edges.append(currentElement.getStateId());
                edges.append(" [style=\"dashed\" weight=\"0\" label=\"covered by\"]\n");
            }

            for (ARGState child : successorFunction.apply(currentElement)) {
                edges.append(determineEdge(highlightEdge, currentElement, child));
                worklist.add(child);
            }
        }
        sb.append(edges);
    }

    private static String determineEdge(final Predicate<? super Pair<ARGState, ARGState>> highlightEdge,
            final ARGState state, final ARGState succesorState) {
        final StringBuilder builder = new StringBuilder();
        builder.append(state.getStateId()).append(" -> ").append(succesorState.getStateId());
        builder.append(" [");

        if (state.getChildren().contains(succesorState)) {
            final CFAEdge edge = state.getEdgeToChild(succesorState);

            if (edge == null) {
                // there is no direct edge between the nodes, use a dummy-edge
                builder.append("style=\"bold\" color=\"blue\" label=\"dummy edge\"");
            } else {
                // edge exists, use info from edge
                boolean colored = highlightEdge.apply(Pair.of(state, succesorState));
                if (colored) {
                    builder.append("color=\"red\" ");
                }
                builder.append("label=\"");
                builder.append("Line ");
                builder.append(edge.getLineNumber());
                builder.append(": ");
                builder.append(edge.getDescription().replaceAll("\n", " ").replace('"', '\''));
                builder.append("\"");
            }
            builder.append(" id=\"");
            builder.append(state.getStateId());
            builder.append(" -> ");
            builder.append(succesorState.getStateId());
            builder.append("\"");
        }

        builder.append("]\n");
        return builder.toString();
    }

    void writeEdge(ARGState start, ARGState end) throws IOException {
        sb.append("" + start.getStateId());
        sb.append(" -> ");
        sb.append("" + end.getStateId());
        sb.append("\n");
    }

    void enterSubgraph(String name, String label) throws IOException {
        sb.append("subgraph ");
        sb.append(name);
        sb.append(" {\n");

        sb.append("label=\"");
        sb.append(label);
        sb.append("\"\n");
    }

    void leaveSubgraph() throws IOException {
        sb.append("}\n");
    }

    void finish() throws IOException {
        sb.append("}\n");
    }

    private static String escapeLabelString(final String rawString) {
        return rawString;
    }

    private static String determineStateHint(final ARGState currentElement) {

        final String stateNodeId = Integer.toString(currentElement.getStateId());
        final String hintNodeId = stateNodeId + "hint";

        String hintLabel = "";
        //    PredicateAbstractState abstraction = AbstractStates.extractStateByType(currentElement, PredicateAbstractState.class);
        //    if (abstraction != null && abstraction.isAbstractionState()) {
        //      final StringBuilder labelBuilder = new StringBuilder();
        //      labelBuilder.append(abstraction.getAbstractionFormula().asFormula().toString());
        //      hintLabel = labelBuilder.toString();
        //    }

        final StringBuilder builder = new StringBuilder();

        if (hintLabel != "") {
            builder.append(" {");
            builder.append(" rank=same;\n");

            builder.append(" ");
            builder.append(stateNodeId);
            builder.append(";\n");

            builder.append(" \"");
            builder.append(hintNodeId);
            builder.append("\" [label=\"");
            builder.append(escapeLabelString(hintLabel));
            builder.append("\", shape=box, style=filled, fillcolor=gray];\n");

            builder.append(" ");
            builder.append(stateNodeId);
            builder.append(" -> ");
            builder.append("\"");
            builder.append(hintNodeId);
            builder.append("\"");
            builder.append(" [arrowhead=none, color=gray, style=solid]");
            builder.append(";\n");

            builder.append(" }\n");
        }

        return builder.toString();
    }

    private static String determineNode(final ARGState currentElement) {
        final StringBuilder builder = new StringBuilder();
        builder.append(currentElement.getStateId());
        builder.append(" [");
        final String color = determineColor(currentElement);
        if (color != null) {
            builder.append("fillcolor=\"").append(color).append("\" ");
        }
        builder.append("label=\"").append(determineLabel(currentElement)).append("\" ");
        builder.append("id=\"").append(currentElement.getStateId()).append("\"]\n");
        return builder.toString();
    }

    private static String determineLabel(ARGState currentElement) {
        StringBuilder builder = new StringBuilder();

        builder.append(currentElement.getStateId());

        CFANode loc = AbstractStates.extractLocation(currentElement);
        if (loc != null) {
            builder.append(" @ ");
            builder.append(loc.toString());
            builder.append("\\n");
            builder.append(loc.getFunctionName());
            if (loc instanceof FunctionEntryNode) {
                builder.append(" entry");
            } else if (loc instanceof FunctionExitNode) {
                builder.append(" exit");
            }
        }

        builder.append("\\n");
        builder.append(currentElement.toDOTLabel());

        return builder.toString().trim();
    }

    private static String determineColor(ARGState currentElement) {
        if (currentElement.isCovered()) {
            return "green";
        }
        if (currentElement.isTarget()) {
            return "red";
        }

        if (!currentElement.wasExpanded()) {
            return "orange";
        }

        if (currentElement.shouldBeHighlighted()) {
            return "cornflowerblue";
        }

        return null;
    }
}