dot: heuristic to switch between circles and ellipses

* src/twaalgos/dotty.cc: Add an option (e) to force elliptic shape, and
a heuristic to choose between circle and ellipse by default.
* src/bin/common_aoutput.cc, src/bin/dstar2tgba.cc: Document 'e'.
* src/taalgos/dotty.cc: Ignore 'e'.
* wrap/python/spot.py (setup): Do not force circular states.  The
default should be fine.
* src/tests/det.test, src/tests/dstar.test, src/tests/monitor.test,
src/tests/neverclaimread.test, src/tests/readsave.test,
src/tests/sccdot.test, src/tests/tgbagraph.test: Adjust expected
results.
* NEWS: Adjust.
This commit is contained in:
Alexandre Duret-Lutz 2015-04-28 18:22:08 +02:00
parent 8aa88c2951
commit a4b63e8e7f
13 changed files with 65 additions and 22 deletions

10
NEWS
View file

@ -187,10 +187,12 @@ New in spot 1.99b (not yet released)
sugar for [:*1..], and corresponds to the operator ⊕ introduced sugar for [:*1..], and corresponds to the operator ⊕ introduced
by Dax et al. (ATVA'09). by Dax et al. (ATVA'09).
- GraphViz output now uses an horizontal layout by default. The - GraphViz output now uses an horizontal layout by default, and
--dot option of the various command-line tools takes an optional also use circular states (unless the automaton has more than 100
parameter to fine-tune the GraphViz output (including vertical states, or uses named-states). The --dot option of the various
layout, round states, named automata, SCC informations, ordered command-line tools takes an optional parameter to fine-tune the
GraphViz output (including vertical layout, forced circular or
elliptic states, named automata, SCC information, ordered
transitions, and different ways to colorize the acceptance transitions, and different ways to colorize the acceptance
sets). The environment variables SPOT_DOTDEFAULT and sets). The environment variables SPOT_DOTDEFAULT and
SPOT_DOTEXTRA can also be used to respectively provide a default SPOT_DOTEXTRA can also be used to respectively provide a default

View file

@ -51,13 +51,14 @@ static const argp_option options[] =
{ {
/**************************************************/ /**************************************************/
{ 0, 0, 0, 0, "Output format:", 3 }, { 0, 0, 0, 0, "Output format:", 3 },
{ "dot", OPT_DOT, "1|a|b|B|c|f(FONT)|h|n|N|o|r|R|s|t|v", { "dot", OPT_DOT, "1|a|b|B|c|e|f(FONT)|h|n|N|o|r|R|s|t|v",
OPTION_ARG_OPTIONAL, OPTION_ARG_OPTIONAL,
"GraphViz's format (default). Add letters for " "GraphViz's format (default). Add letters for "
"(1) force numbered states, " "(1) force numbered states, "
"(a) acceptance display, (b) acceptance sets as bullets, " "(a) acceptance display, (b) acceptance sets as bullets, "
"(B) bullets except for Büchi/co-Büchi automata, " "(B) bullets except for Büchi/co-Büchi automata, "
"(c) circular nodes, (f(FONT)) use FONT, (h) horizontal layout, " "(c) force circular nodes, (e) force elliptic nodes, "
"(f(FONT)) use FONT, (h) horizontal layout, "
"(v) vertical layout, (n) with name, (N) without name, " "(v) vertical layout, (n) with name, (N) without name, "
"(o) ordered transitions, " "(o) ordered transitions, "
"(r) rainbow colors for acceptance sets, " "(r) rainbow colors for acceptance sets, "

View file

@ -73,13 +73,14 @@ static const argp_option options[] =
"of the given property)", 0 }, "of the given property)", 0 },
/**************************************************/ /**************************************************/
{ 0, 0, 0, 0, "Output format:", 3 }, { 0, 0, 0, 0, "Output format:", 3 },
{ "dot", OPT_DOT, "1|a|b|B|c|f(FONT)|h|n|N|o|r|R|s|t|v", { "dot", OPT_DOT, "1|a|b|B|c|e|f(FONT)|h|n|N|o|r|R|s|t|v",
OPTION_ARG_OPTIONAL, OPTION_ARG_OPTIONAL,
"GraphViz's format (default). Add letters for " "GraphViz's format (default). Add letters for "
"(1) force numbered states, " "(1) force numbered states, "
"(a) acceptance display, (b) acceptance sets as bullets, " "(a) acceptance display, (b) acceptance sets as bullets, "
"(B) bullets except for Büchi automata, " "(B) bullets except for Büchi/co-Büchi automata, "
"(c) circular nodes, (f(FONT)) use FONT, (h) horizontal layout, " "(c) force circular nodes, (e) force elliptic nodes, "
"(f(FONT)) use FONT, (h) horizontal layout, "
"(v) vertical layout, (n) with name, (N) without name, " "(v) vertical layout, (n) with name, (N) without name, "
"(o) ordered transitions, " "(o) ordered transitions, "
"(r) rainbow colors for acceptance sets, " "(r) rainbow colors for acceptance sets, "

View file

@ -88,6 +88,7 @@ namespace spot
case 'a': case 'a':
case 'b': case 'b':
case 'B': case 'B':
case 'e':
case 'n': case 'n':
case 'N': case 'N':
case 'o': case 'o':

View file

@ -118,6 +118,7 @@ run 0 ../ltl2tgba -x -DC 'GFa & XGFb' > out.tgba
cat >ex.tgba <<EOF cat >ex.tgba <<EOF
digraph G { digraph G {
rankdir=LR rankdir=LR
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 0 I -> 0
0 [label="0"] 0 [label="0"]

View file

@ -61,6 +61,7 @@ run 0 ../ltl2tgba -XD dra.dstar | tee stdout
cat >expected <<EOF cat >expected <<EOF
digraph G { digraph G {
rankdir=LR rankdir=LR
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 0 I -> 0
0 [label="0"] 0 [label="0"]
@ -82,6 +83,7 @@ run 0 ../ltl2tgba -XDD dra.dstar | tee stdout
cat >expected <<EOF cat >expected <<EOF
digraph G { digraph G {
rankdir=LR rankdir=LR
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 0 I -> 0
0 [label="0"] 0 [label="0"]
@ -126,6 +128,7 @@ run 0 ../ltl2tgba -XDB dsa.dstar | tee stdout
cat >expected <<EOF cat >expected <<EOF
digraph G { digraph G {
rankdir=LR rankdir=LR
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 0 I -> 0
0 [label="0"] 0 [label="0"]
@ -215,6 +218,7 @@ run 0 ../ltl2tgba -XDD dra.dstar | tee stdout
cat >expected <<EOF cat >expected <<EOF
digraph G { digraph G {
rankdir=LR rankdir=LR
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 0 I -> 0
0 [label="0"] 0 [label="0"]
@ -264,6 +268,7 @@ digraph G {
rankdir=LR rankdir=LR
label="aut.dsa" label="aut.dsa"
labelloc="t" labelloc="t"
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 0 I -> 0
0 [label="0"] 0 [label="0"]

View file

@ -34,6 +34,7 @@ expect()
expect ../../bin/ltl2tgba --monitor a <<EOF expect ../../bin/ltl2tgba --monitor a <<EOF
digraph G { digraph G {
rankdir=LR rankdir=LR
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 1 I -> 1
0 [label="0"] 0 [label="0"]

View file

@ -134,6 +134,7 @@ run 0 ../ltl2tgba -XN input > stdout
cat >expected <<EOF cat >expected <<EOF
digraph G { digraph G {
rankdir=LR rankdir=LR
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 0 I -> 0
0 [label="0", peripheries=2] 0 [label="0", peripheries=2]

View file

@ -349,6 +349,7 @@ digraph G {
rankdir=LR rankdir=LR
label="Inf(0)&Inf(1)" label="Inf(0)&Inf(1)"
labelloc="t" labelloc="t"
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 0 I -> 0
0 [label="0"] 0 [label="0"]
@ -367,6 +368,7 @@ digraph G {
rankdir=LR rankdir=LR
label="G(Fa & Fb)\nInf(⓿)&Inf(❶)" label="G(Fa & Fb)\nInf(⓿)&Inf(❶)"
labelloc="t" labelloc="t"
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 0 I -> 0
0 [label="0"] 0 [label="0"]
@ -379,7 +381,7 @@ EOF
diff output expected diff output expected
SPOT_DOTDEFAULT=bra $ltl2tgba --dot='c.f(Lato)' 'GFa & GFb' >output SPOT_DOTDEFAULT=bra $ltl2tgba --dot='e.f(Lato)' 'GFa & GFb' >output
cat output cat output
zero='<font color="#5DA5DA">⓿</font>' zero='<font color="#5DA5DA">⓿</font>'
@ -389,7 +391,6 @@ digraph G {
rankdir=LR rankdir=LR
label=<Inf($zero)&amp;Inf($one)> label=<Inf($zero)&amp;Inf($one)>
labelloc="t" labelloc="t"
node [shape="circle"]
fontname="Lato" fontname="Lato"
node [fontname="Lato"] node [fontname="Lato"]
edge [fontname="Lato"] edge [fontname="Lato"]
@ -515,6 +516,7 @@ digraph G {
rankdir=LR rankdir=LR
label="Fin(⓿) | (Fin(❶) & Inf(❷)) | Fin(❸)" label="Fin(⓿) | (Fin(❶) & Inf(❷)) | Fin(❸)"
labelloc="t" labelloc="t"
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
0 [label="0"] 0 [label="0"]
1 [label="1\n⓿❸"] 1 [label="1\n⓿❸"]
@ -529,7 +531,8 @@ digraph G {
} }
EOF EOF
# This should remove the state names # This should remove the state names, and automatically use circled
# states.
$autfilt --dot=bao1 in | grep -v '>' >out $autfilt --dot=bao1 in | grep -v '>' >out
diff out expected2 diff out expected2

View file

@ -76,6 +76,7 @@ digraph G {
rankdir=LR rankdir=LR
label="Fin(2) & (Inf(0)&Inf(1))" label="Fin(2) & (Inf(0)&Inf(1))"
labelloc="t" labelloc="t"
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 1 I -> 1
subgraph cluster_0 { subgraph cluster_0 {

View file

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2014 Laboratoire de Recherche et Développement de # Copyright (C) 2014, 2015 Laboratoire de Recherche et Développement
# l'Epita (LRDE). # de l'Epita (LRDE).
# #
# This file is part of Spot, a model checking library. # This file is part of Spot, a model checking library.
# #
@ -35,6 +35,7 @@ run 0 ../tgbagraph | tee stdout
cat >expected <<EOF cat >expected <<EOF
digraph G { digraph G {
rankdir=LR rankdir=LR
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 0 I -> 0
0 [label="0"] 0 [label="0"]
@ -50,6 +51,7 @@ digraph G {
} }
digraph G { digraph G {
rankdir=LR rankdir=LR
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 0 I -> 0
0 [label="0"] 0 [label="0"]
@ -63,6 +65,7 @@ digraph G {
} }
digraph G { digraph G {
rankdir=LR rankdir=LR
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 0 I -> 0
0 [label="0"] 0 [label="0"]
@ -75,6 +78,7 @@ digraph G {
} }
digraph G { digraph G {
rankdir=LR rankdir=LR
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 0 I -> 0
0 [label="0"] 0 [label="0"]
@ -90,6 +94,7 @@ digraph G {
} }
digraph G { digraph G {
rankdir=LR rankdir=LR
node [shape="circle"]
I [label="", style=invis, width=0] I [label="", style=invis, width=0]
I -> 0 I -> 0
0 [label="0"] 0 [label="0"]

View file

@ -47,7 +47,8 @@ namespace spot
bool opt_force_acc_trans_ = false; bool opt_force_acc_trans_ = false;
bool opt_horizontal_ = true; bool opt_horizontal_ = true;
bool opt_name_ = false; bool opt_name_ = false;
bool opt_circles_ = false; enum { ShapeAuto = 0, ShapeCircle, ShapeEllipse }
opt_shape_ = ShapeAuto;
bool opt_show_acc_ = false; bool opt_show_acc_ = false;
bool mark_states_ = false; bool mark_states_ = false;
bool opt_scc_ = false; bool opt_scc_ = false;
@ -123,10 +124,10 @@ namespace spot
opt_bullet_but_buchi = true; opt_bullet_but_buchi = true;
break; break;
case 'c': case 'c':
opt_circles_ = true; opt_shape_ = ShapeCircle;
break; break;
case 'h': case 'e':
opt_horizontal_ = true; opt_shape_ = ShapeEllipse;
break; break;
case 'f': case 'f':
if (*options != '(') if (*options != '(')
@ -141,6 +142,9 @@ namespace spot
options = end + 1; options = end + 1;
} }
break; break;
case 'h':
opt_horizontal_ = true;
break;
case 'n': case 'n':
opt_name_ = true; opt_name_ = true;
break; break;
@ -275,7 +279,6 @@ namespace spot
aut_->get_acceptance().used_inf_fin_sets(); aut_->get_acceptance().used_inf_fin_sets();
if (opt_bullet && aut_->acc().num_sets() <= MAX_BULLET) if (opt_bullet && aut_->acc().num_sets() <= MAX_BULLET)
opt_all_bullets = true; opt_all_bullets = true;
os_ << "digraph G {\n"; os_ << "digraph G {\n";
if (opt_horizontal_) if (opt_horizontal_)
os_ << " rankdir=LR\n"; os_ << " rankdir=LR\n";
@ -317,8 +320,18 @@ namespace spot
} }
os_ << " labelloc=\"t\"\n"; os_ << " labelloc=\"t\"\n";
} }
if (opt_circles_) switch (opt_shape_)
os_ << " node [shape=\"circle\"]\n"; {
case ShapeCircle:
os_ << " node [shape=\"circle\"]\n";
break;
case ShapeEllipse:
// Do not print anything. Ellipse is
// the default shape used by GraphViz.
break;
case ShapeAuto:
SPOT_UNREACHABLE();
}
if (!opt_font_.empty()) if (!opt_font_.empty())
os_ << " fontname=\"" << opt_font_ os_ << " fontname=\"" << opt_font_
<< "\"\n node [fontname=\"" << opt_font_ << "\"\n node [fontname=\"" << opt_font_
@ -452,8 +465,16 @@ namespace spot
if (opt_name_) if (opt_name_)
name_ = aut_->get_named_prop<std::string>("automaton-name"); name_ = aut_->get_named_prop<std::string>("automaton-name");
mark_states_ = !opt_force_acc_trans_ && aut_->has_state_based_acc(); mark_states_ = !opt_force_acc_trans_ && aut_->has_state_based_acc();
if (opt_shape_ == ShapeAuto)
{
if (sn_ || aut->num_states() > 100)
opt_shape_ = ShapeEllipse;
else
opt_shape_ = ShapeCircle;
}
auto si = auto si =
std::unique_ptr<scc_info>(opt_scc_ ? new scc_info(aut) : nullptr); std::unique_ptr<scc_info>(opt_scc_ ? new scc_info(aut) : nullptr);
start(); start();
if (si) if (si)
{ {

View file

@ -48,7 +48,7 @@ def setup(**kwargs):
kwargs.get('fillcolor', '#ffffaa')) kwargs.get('fillcolor', '#ffffaa'))
bullets = 'B' if kwargs.get('bullets', True) else '' bullets = 'B' if kwargs.get('bullets', True) else ''
d = 'rcf({})'.format(kwargs.get('font', 'Lato')) + bullets d = 'rf({})'.format(kwargs.get('font', 'Lato')) + bullets
os.environ['SPOT_DOTDEFAULT'] = d os.environ['SPOT_DOTDEFAULT'] = d
# Global BDD dict so that we do not have to create one in user code. # Global BDD dict so that we do not have to create one in user code.