/** * */ package de.uni_freiburg.informatik.ultimate.lib.pea.modelchecking; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.util.Iterator; import java.util.List; import de.uni_freiburg.informatik.ultimate.lib.pea.Decision; import de.uni_freiburg.informatik.ultimate.lib.pea.Phase; import de.uni_freiburg.informatik.ultimate.lib.pea.PhaseEventAutomata; import de.uni_freiburg.informatik.ultimate.lib.pea.Transition; /** * The class DOTWriter offers functionality to convert a Phase Event automaton object into a Dot-File. The * dot-file can then be visualized in Graphviz; Note that Graphviz cannot depict the math formulas(at least it cannot do * so under windows); However you can convert via dot2tex the dotfiles to texfiles (using the pgf-library) and get a * visualization via tex (including the math-formulas) * * For GraphViz see: http://www.graphviz.org/ For Dot2Tex see: http://www.fauskes.net/code/dot2tex/documentation/ For * PGF/TIK see: http://www.ctan.org/tex-archive/help/Catalogue/entries/pgf.html * * The Converter is called, e.g. with: // DOTWriter dotwriter = new DOTWriter("C:/Test.dot", ctParallel); // * dotwriter.write(); * * @author Amalinda Oertel March 2010 * * @see de.uni_freiburg.informatik.ultimate.lib.pea.CDD */ public class DOTWriter extends TCSWriter { public static class DOTString { public static final String DOT_NODEDEF_START = " [width=0.5pt, texlbl=\"$\\substack{"; public static final String DOT_NODEDEF_END = " }$\"]; \n"; public static final String TO = " -> "; public static final String STOP = ";"; public static final String DOT_LABEL_START = " [label=\" \", width =1, texlbl=\"$\\substack{"; public static final String DOT_LABEL_START1 = " [label=\" "; public static final String DOT_LABEL_START2 = " \", width =1, texlbl=\"$\\substack{"; public static final String DOT_LABEL_END = "}$\"]; \n"; } /** * FileWriter to output file. */ protected FileWriter writer; protected boolean rename; protected PhaseEventAutomata pea2write; public DOTWriter(final String fileName, final PhaseEventAutomata pea) { super(fileName); pea2write = pea; } public DOTWriter(final String fileName) { super(fileName); } /** * Constructor setting output file name and rename flag that indicates whether original location names have to be * used or whether the locations are renamed into default names. * * @param file * @param rename */ public DOTWriter(final String destfile, final boolean rename, final PhaseEventAutomata pea) { this(destfile, pea); this.rename = rename; } public void write(final String fileName, final PhaseEventAutomata pea) { try { pea2write = pea; writer = new FileWriter(fileName); // init(); writePreamble(); writeInitialTransitions(); writeTransitions(); writeClose(); writer.flush(); writer.close(); System.out.println("Successfully written to " + fileName); } catch (final IOException e) { throw new RuntimeException(e); } } @Override public void write() { try { writer = new FileWriter(mFileName); // init(); writePreamble(); writeInitialTransitions(); writeTransitions(); writeClose(); writer.flush(); writer.close(); System.out.println("Successfully written to " + mFileName); } catch (final IOException e) { throw new RuntimeException(e); } } @Override protected void writeAndDelimiter(final Writer writer) throws IOException { // TODO Auto-generated method stub } @Override protected void writeDecision(final Decision decision, final int child, final Writer writer) throws IOException { // TODO Auto-generated method stub } protected void writePreamble() throws IOException { writer.write("/* Preamble:\n" + " File automatically generated via DOTWriter\n\n */" + " digraph G { \n"); } /** * instead of initial edges we construct a new initial node "init" and write edges to the initial nodes * * As Tex interprets "_" as command, we need to delete(or change) it from the names of the states. * * @throws IOException * thrown if writing of output file fails */ protected void writeInitialTransitions() throws IOException { final List init = pea2write.getInit(); for (final Phase element : init) { String initState = element.toString(); initState = initState.replace("_", ""); writer.write("null" + initState + " [shape = plaintext label=\"\"] \n"); writer.write("null" + initState + DOTString.TO + initState + DOTString.STOP + "\n"); // this.writer.write("init "+ DOTString.TO + initState + DOTString.STOP + "\n"); // \node[initial,state] (A) {$q_a$}; } } protected void writeClose() throws IOException { writer.write("\n }"); } /** * To get the edge labels more readable I'm using \substack and \\\\ for new lines As Tex interprets "_" as command, * we need to delete(or change) it from the names of the states. */ protected void writeTransitions() throws IOException { final List phases = pea2write.getPhases(); for (int i = 0; i < phases.size(); i++) { final Phase currentPhase = phases.get(i); String location = currentPhase.getName(); location = location.replace("_", ""); String clock = currentPhase.getClockInvariant().toTexString(); clock = clock.replace("_", ""); String predicate = currentPhase.getStateInvariant().toTexString(); predicate = predicate.replace("\\wedge", "\\wedge \\\\"); predicate = predicate.replace("\\vee", "\\vee \\\\"); predicate = predicate.replace("_", ""); writer.write(location + DOTString.DOT_NODEDEF_START + location + " \\\\ " + predicate + " \\\\ " + clock + DOTString.DOT_NODEDEF_END); final List transitions = currentPhase.getTransitions(); final Iterator it = transitions.iterator(); while (it.hasNext()) { final Transition t = (Transition) it.next(); String start = t.getSrc().getName(); start = start.replace("_", ""); String end = t.getDest().getName(); end = end.replace("_", ""); String guard = t.getGuard().toTexString(); guard = guard.replace("_", ""); guard = guard.replace("\\wedge", "\\wedge \\\\"); final String[] reset = t.getResets(); String guard2 = " "; for (int j = guard.length(); j > 0; j--) { guard2 = guard2.concat(" "); } String result = " "; if (reset.length > 0) { for (final String element : reset) { result = result + element + " := 0 "; } } result = result.replace("_", ""); writer.write(" " + start + DOTString.TO + end + DOTString.DOT_LABEL_START1 + guard2 + DOTString.DOT_LABEL_START2 + guard + " \\\\ " + result + DOTString.DOT_LABEL_END); } } } }