All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.automatalib.util.graphs.dot.GraphDOT Maven / Gradle / Ivy

Go to download

This artifact provides various common utility operations for analyzing and manipulating automata and graphs, such as traversal, minimization and copying.

There is a newer version: 0.11.0
Show newest version
/* Copyright (C) 2013 TU Dortmund
 * This file is part of AutomataLib, http://www.automatalib.net/.
 * 
 * AutomataLib is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 3.0 as published by the Free Software Foundation.
 * 
 * AutomataLib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with AutomataLib; if not, see
 * http://www.gnu.de/documents/lgpl.en.html.
 */
package net.automatalib.util.graphs.dot;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.Flushable;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.automatalib.AutomataLibSettings;
import net.automatalib.automata.Automaton;
import net.automatalib.automata.graphs.TransitionEdge;
import net.automatalib.commons.dotutil.DOT;
import net.automatalib.commons.util.mappings.MutableMapping;
import net.automatalib.commons.util.strings.StringUtil;
import net.automatalib.graphs.Graph;
import net.automatalib.graphs.UndirectedGraph;
import net.automatalib.graphs.concepts.GraphViewable;
import net.automatalib.graphs.dot.AggregateDOTHelper;
import net.automatalib.graphs.dot.DefaultDOTHelper;
import net.automatalib.graphs.dot.GraphDOTHelper;
import net.automatalib.util.automata.Automata;


/**
 * Methods for rendering a {@link Graph} or {@link Automaton} in the GraphVIZ DOT format.
 * 

* This class does not take care of actually processing the generated DOT data. For this, * please take a look at the automata-commons-dotutil artifact. * * @author Malte Isberner * */ public abstract class GraphDOT { static { AutomataLibSettings settings = AutomataLibSettings.getInstance(); String dotExePath = settings.getProperty("dot.exe.dir"); String dotExeName = settings.getProperty("dot.exe.name", "dot"); String dotExe = dotExeName; if (dotExePath != null) { Path dotBasePath = FileSystems.getDefault().getPath(dotExePath); Path resolvedDotPath = dotBasePath.resolve(dotExeName); dotExe = resolvedDotPath.toString(); } DOT.setDotExe(dotExe); } public static boolean isDotUsable() { return DOT.checkUsable(); } public static void write(GraphViewable gv, Appendable a) throws IOException { Graph graph = gv.graphView(); write(graph, a); } /** * Renders a {@link Graph} in the GraphVIZ DOT format. * @param graph the graph to render * @param a the appendable to write to. * @throws IOException if writing to a fails. */ @SafeVarargs public static void write(Graph graph, Appendable a, GraphDOTHelper ...additionalHelpers) throws IOException { GraphDOTHelper helper = graph.getGraphDOTHelper(); writeRaw(graph, helper, a, additionalHelpers); } /** * Renders an {@link Automaton} in the GraphVIZ DOT format. * * @param automaton the automaton to render. * @param helper the helper to use for rendering * @param inputAlphabet the input alphabet to consider * @param a the appendable to write to. * @throws IOException if writing to a fails. */ @SafeVarargs public static void write(Automaton automaton, GraphDOTHelper> helper, Collection inputAlphabet, Appendable a, GraphDOTHelper> ...additionalHelpers) throws IOException { Graph> ag = Automata.asGraph(automaton, inputAlphabet); writeRaw(ag, helper, a, additionalHelpers); } /** * Renders an {@link Automaton} in the GraphVIZ DOT format. * * @param automaton the automaton to render. * @param inputAlphabet the input alphabet to consider * @param a the appendable to write to * @throws IOException if writing to a fails */ @SafeVarargs public static void write(Automaton automaton, Collection inputAlphabet, Appendable a, GraphDOTHelper> ...additionalHelpers) throws IOException { write(automaton.transitionGraphView(inputAlphabet), a, additionalHelpers); } @SafeVarargs public static void writeRaw(Graph graph, GraphDOTHelper helper, Appendable a, GraphDOTHelper ...additionalHelpers) throws IOException { List> helpers = new ArrayList<>(additionalHelpers.length + 1); helpers.add(helper); helpers.addAll(Arrays.asList(additionalHelpers)); writeRaw(graph, a, helpers); } public static void writeRaw(Graph graph, Appendable a, List> helpers) throws IOException { AggregateDOTHelper aggHelper = new AggregateDOTHelper<>(helpers); writeRaw(graph, aggHelper, a); } /** * Renders a {@link Graph} in the GraphVIZ DOT format. * * @param graph the graph to render * @param dotHelper the helper to use for rendering * @param a the appendable to write to * @throws IOException if writing to a fails */ public static void writeRaw(Graph graph, GraphDOTHelper dotHelper, Appendable a) throws IOException { if(dotHelper == null) dotHelper = new DefaultDOTHelper(); boolean directed = true; if(graph instanceof UndirectedGraph) directed = false; if(directed) a.append("di"); a.append("graph g {\n"); Map props = new HashMap<>(); dotHelper.getGlobalNodeProperties(props); if(!props.isEmpty()) { a.append('\t').append("node"); appendParams(props, a); a.append(";\n"); } props.clear(); dotHelper.getGlobalEdgeProperties(props); if(!props.isEmpty()) { a.append('\t').append("edge"); appendParams(props, a); a.append(";\n"); } dotHelper.writePreamble(a); a.append('\n'); MutableMapping nodeNames = graph.createStaticNodeMapping(); int i = 0; for(N node : graph) { props.clear(); if(!dotHelper.getNodeProperties(node, props)) continue; String id = "s" + i++; a.append('\t').append(id); appendParams(props, a); a.append(";\n"); nodeNames.put(node, id); } for(N node : graph) { String srcId = nodeNames.get(node); if(srcId == null) continue; Collection outEdges = graph.getOutgoingEdges(node); if(outEdges.isEmpty()) continue; for(E e : outEdges) { N tgt = graph.getTarget(e); String tgtId = nodeNames.get(tgt); if(tgtId == null) continue; if(!directed && tgtId.compareTo(srcId) < 0) continue; props.clear(); if(!dotHelper.getEdgeProperties(node, e, tgt, props)) continue; a.append('\t').append(srcId).append(' '); if(directed) a.append("-> "); else a.append("-- "); a.append(tgtId); appendParams(props, a); a.append(";\n"); } } a.append('\n'); dotHelper.writePostamble(nodeNames, a); a.append("}\n"); if (a instanceof Flushable) { ((Flushable) a).flush(); } } public static void writeToFileRaw(Graph graph, GraphDOTHelper dotHelper, File file) throws IOException { try(BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { writeRaw(graph, dotHelper, writer); } } private static void appendParams(Map params, Appendable a) throws IOException { if(params == null || params.isEmpty()) return; a.append(" ["); boolean first = true; for(Map.Entry e : params.entrySet()) { if(first) first = false; else a.append(' '); String key = e.getKey(); String value = e.getValue(); a.append(e.getKey()).append("="); // HTML labels have to be enclosed in <> instead of "" if(key.equals(GraphDOTHelper.CommonAttrs.LABEL) && value.toUpperCase().startsWith("")) a.append('<').append(value.substring(6)).append('>'); else StringUtil.enquote(e.getValue(), a); } a.append(']'); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy