Commit a4b63e8e authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz
Browse files

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.
parent 8aa88c29
...@@ -187,10 +187,12 @@ New in spot 1.99b (not yet released) ...@@ -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
......
...@@ -51,13 +51,14 @@ static const argp_option options[] = ...@@ -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, "
......
...@@ -73,13 +73,14 @@ static const argp_option options[] = ...@@ -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, "
......
...@@ -88,6 +88,7 @@ namespace spot ...@@ -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':
......
...@@ -118,6 +118,7 @@ run 0 ../ltl2tgba -x -DC 'GFa & XGFb' > out.tgba ...@@ -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"]
......
...@@ -61,6 +61,7 @@ run 0 ../ltl2tgba -XD dra.dstar | tee stdout ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 { ...@@ -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"]
......
...@@ -34,6 +34,7 @@ expect() ...@@ -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"]
......
...@@ -134,6 +134,7 @@ run 0 ../ltl2tgba -XN input > stdout ...@@ -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]
......
...@@ -349,6 +349,7 @@ digraph G { ...@@ -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 { ...@@ -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 ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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
......
...@@ -76,6 +76,7 @@ digraph G { ...@@ -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 {
......
#!/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 ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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"]
......
...@@ -47,7 +47,8 @@ namespace spot ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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)
{ {
......
...@@ -48,7 +48,7 @@ def setup(**kwargs): ...@@ -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.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment