dot: use tooltips with option "1"

Fixes #327.

* spot/twaalgos/dot.cc: Emit a tooltip="..." for state names and
labels that are disabled by option "1".
* doc/org/tut51.org, tests/python/product.ipynb, NEWS: Discuss this.
* tests/core/readsave.test, tests/python/alternation.ipynb,
tests/python/automata.ipynb: Adjust test cases.
This commit is contained in:
Alexandre Duret-Lutz 2018-04-06 15:03:04 +02:00
parent 99876048ed
commit 2775b0abc8
7 changed files with 2676 additions and 2103 deletions

6
NEWS
View file

@ -14,6 +14,12 @@ New in spot 2.5.2.dev (not yet released)
the command-line tools, as well as the various way to display
automata using the Python bindings.
- When option "1" is passed to print_dot() to hide state names
and force the display of state numbers, the actual state names
is now moved to the "tooltip" field of the state. The SVG
files produced by "dot -Tsvg" will show those as popups.
This is also done for state labels of kripke structures.
- cleanup_parity() and cleanup_parity_here() are smarter and now
remove from the acceptance condition the parity colors that are
not used in the automaton.

View file

@ -469,13 +469,15 @@ counterexample:
With a small variant of the above code, we could also display the
counterexample on the state space, but only because our state space is
so small: displaying large state spaces is not sensible. Besides, highlighting
a run only works on =twa_graph= automata, so we need to convert the
Kripke structure to a =twa_graph=: this can be done with =make_twa_graph()=. But
now =k= is no longer a Kripke structure (also not generated
on-the-fly anymore), so the =print_dot()= function will display it as
a classical automaton with conditions on edges rather than state:
passing the option "~k~" to =print_dot()= will fix that.
so small: displaying large state spaces is not sensible. Besides,
highlighting a run only works on =twa_graph= automata, so we need to
convert the Kripke structure to a =twa_graph=: this can be done with
=make_twa_graph()=. But now =k= is no longer a Kripke structure (also
not generated on-the-fly anymore), so the =print_dot()= function will
display it as a classical automaton with conditions on edges rather
than state: passing the option "~k~" to =print_dot()= will fix that.
We also pass option "~A~" to hide the acceptance condition (which is
=t=, i.e., accepting every infinite run).
#+NAME: demo-3-aux
#+BEGIN_SRC C++ :exports none :noweb strip-export
@ -515,7 +517,7 @@ passing the option "~k~" to =print_dot()= will fix that.
if (auto run = k->intersecting_run(af))
{
run->highlight(5); // 5 is a color number.
spot::print_dot(std::cout, k, ".k");
spot::print_dot(std::cout, k, ".kA");
}
}
#+END_SRC
@ -527,6 +529,58 @@ $txt
#+RESULTS:
[[file:kripke-3.svg]]
Note that labeling states with names (the first line) and the
valuation of all atomic propositions (the second line) will quickly
produce graphs with large nodes that are problematic to render. A
trick to reduce the clutter and the size of the graph is to pass
option "~1~" to =print_dot()=, changing the above call to
src_cpp[:exports code]{spot::print_dot(std::cout, k, ".kA1");}. This
will cause all states to be numbered instead, but if the automaton is
rendered as an SVG figure, the old label will still appear as a
tooltip when the mouse is over a state. Try that on the following
figure:
#+NAME: demo-3b
#+BEGIN_SRC C++ :exports none :noweb strip-export :results verbatim
#include <spot/twaalgos/dot.hh>
#include <spot/tl/parse.hh>
#include <spot/twaalgos/translate.hh>
#include <spot/twa/twaproduct.hh>
#include <spot/twaalgos/emptiness.hh>
<<demo-3-aux>>
int main()
{
auto d = spot::make_bdd_dict();
// Parse the input formula.
spot::parsed_formula pf = spot::parse_infix_psl("GF(odd_x) -> GF(odd_y)");
if (pf.format_errors(std::cerr))
return 1;
// Translate its negation.
spot::formula f = spot::formula::Not(pf.f);
spot::twa_graph_ptr af = spot::translator(d).run(f);
// Convert demo_kripke into an explicit graph
spot::twa_graph_ptr k =
spot::make_twa_graph(std::make_shared<demo_kripke>(d),
spot::twa::prop_set::all(), true);
// Find a run of or demo_kripke that intersects af.
if (auto run = k->intersecting_run(af))
{
run->highlight(5); // 5 is a color number.
spot::print_dot(std::cout, k, ".kA1");
}
}
#+END_SRC
#+BEGIN_SRC dot :file kripke-3b.svg :cmd circo :var txt=demo-3b :exports results
$txt
#+END_SRC
#+RESULTS:
[[file:kripke-3b.svg]]
* Possible improvements
The on-the-fly interface, especially as implemented here, involves a

View file

@ -112,7 +112,7 @@ namespace spot
std::string opt_font_;
std::string opt_node_color_;
std::ostream& os_;
bool opt_want_state_names_ = true;
bool inline_state_names_ = true;
unsigned max_states_ = -1U; // related to max_states_given_
bool opt_shared_univ_dest_ = true;
@ -189,7 +189,7 @@ namespace spot
opt_numbered_edges_ = true;
break;
case '1':
opt_want_state_names_ = false;
inline_state_names_ = false;
break;
case 'a':
opt_show_acc_ = true;
@ -576,19 +576,39 @@ namespace spot
os_ << '}' << std::endl;
}
bool print_state_name(std::ostream& os, unsigned s,
bool force_text = false) const
{
if (sn_ && s < sn_->size() && !(*sn_)[s].empty())
{
if (force_text)
escape_str(os, (*sn_)[s]);
else
escape_for_output(os, (*sn_)[s]);
}
else if (sprod_)
{
os << (*sprod_)[s].first << ',' << (*sprod_)[s].second;
}
else
{
return false;
}
return true;
}
void
process_state(unsigned s)
{
os_ << " " << s << " [" << label_pre_;
if (sn_ && s < sn_->size() && !(*sn_)[s].empty())
escape_for_output(os_, (*sn_)[s]);
else if (sprod_)
os_ << (*sprod_)[s].first << ',' << (*sprod_)[s].second;
else
if (!(inline_state_names_ && print_state_name(os_, s)))
os_ << s;
if (orig_ && s < orig_->size())
os_ << " (" << (*orig_)[s] << ')';
bool include_state_labels =
opt_state_labels_ && (inline_state_names_ || opt_latex_);
if (mark_states_ && !dcircles_)
{
acc_cond::mark_t acc = {};
@ -603,13 +623,13 @@ namespace spot
os_ << nl_;
output_mark(acc);
}
if (opt_state_labels_)
if (include_state_labels)
format_state_label(os_ << nl_, s);
os_ << label_post_;
}
else
{
if (opt_state_labels_)
if (include_state_labels)
format_state_label(os_ << nl_, s);
os_ << label_post_;
// Use state_acc_sets(), not state_is_accepting() because
@ -630,6 +650,21 @@ namespace spot
<< '"';
}
}
if (!inline_state_names_ && (sn_ || sprod_ || opt_state_labels_)
&& !opt_latex_)
{
std::ostringstream os;
bool nonempty = print_state_name(os, s, true);
if (opt_state_labels_)
{
if (nonempty)
os << '\n';
format_state_label(os, s);
nonempty = true;
}
if (nonempty)
os_ << ", tooltip=\"" << os.str() << '"';
}
os_ << "]\n";
if (incomplete_ && incomplete_->find(s) != incomplete_->end())
os_ << " u" << s << " [label=\"...\", shape=none, width=0, height=0"
@ -707,8 +742,7 @@ namespace spot
void print(const const_twa_graph_ptr& aut)
{
aut_ = aut;
if (opt_want_state_names_)
{
sn_ = aut->get_named_prop<std::vector<std::string>>("state-names");
// We have no names. Do we have product sources?
if (!sn_)
@ -719,7 +753,7 @@ namespace spot
if (sprod_ && aut->num_states() != sprod_->size())
sprod_ = nullptr;
}
}
if (opt_orig_show_)
orig_ = aut->get_named_prop<std::vector<unsigned>>("original-states");
if (opt_state_labels_)
@ -758,8 +792,10 @@ namespace spot
&& (aut_->acc().is_buchi() || aut_->acc().is_co_buchi()));
if (opt_shape_ == ShapeAuto)
{
if (sn_ || sprod_ || aut->num_states() > 100
|| opt_state_labels_ || orig_)
if ((inline_state_names_ && (sn_ || sprod_ || opt_state_labels_))
|| (opt_state_labels_ && opt_latex_)
|| aut->num_states() > 100
|| orig_)
{
opt_shape_ = ShapeEllipse;
// If all state names are short, prefer circles.

View file

@ -529,10 +529,10 @@ digraph G {
node [shape="circle"]
I [label="", style=invis, width=0]
0 [label="0"]
1 [label="1\n⓿❸"]
1 [label="1\n⓿❸", tooltip="test me"]
2 [label="2\n⓿❷❸"]
3 [label="3\n❸"]
4 [label="4\n❷❸"]
4 [label="4\n❷❸", tooltip="hihi"]
5 [label="5\n❶❸"]
6 [label="6\n⓿"]
7 [label="7\n⓿❷"]

File diff suppressed because it is too large Load diff

View file

@ -164,7 +164,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde206230c0> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec2fef30> >"
]
},
"execution_count": 2,
@ -604,7 +604,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2053ec60> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec222d80> >"
]
},
"execution_count": 6,
@ -681,7 +681,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2053ed50> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec222b40> >"
]
},
"execution_count": 7,
@ -765,7 +765,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2053e870> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec2229c0> >"
]
},
"execution_count": 8,
@ -1287,7 +1287,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2055f840> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec245780> >"
]
},
"execution_count": 12,
@ -1402,7 +1402,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2055f4e0> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec245060> >"
]
},
"execution_count": 13,
@ -1534,7 +1534,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2055f9c0> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec245900> >"
]
},
"execution_count": 14,
@ -1647,7 +1647,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2055f870> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec2459c0> >"
]
},
"execution_count": 15,
@ -2193,7 +2193,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2055f990> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec222960> >"
]
},
"execution_count": 16,
@ -2405,7 +2405,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2055f090> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec245b40> >"
]
},
"metadata": {},
@ -2556,7 +2556,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2053ea50> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec232180> >"
]
},
"metadata": {},
@ -2729,7 +2729,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2055fc60> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec245c90> >"
]
},
"metadata": {},
@ -2905,7 +2905,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2055fb70> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec245bd0> >"
]
},
"metadata": {},
@ -3092,7 +3092,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2055ff00> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec245e40> >"
]
},
"execution_count": 21,
@ -3169,7 +3169,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2055ff90> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec222e40> >"
]
},
"execution_count": 22,
@ -3458,8 +3458,11 @@
"<!-- 0 -->\n",
"<g class=\"node\" id=\"node2\">\n",
"<title>0</title>\n",
"<g id=\"a_node2\"><a xlink:title=\"1,1\">\n",
"<ellipse cx=\"56\" cy=\"-118\" fill=\"#ffffaa\" rx=\"18\" ry=\"18\" stroke=\"#000000\"/>\n",
"<text fill=\"#000000\" font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"56\" y=\"-114.3\">0</text>\n",
"</a>\n",
"</g>\n",
"</g>\n",
"<!-- I&#45;&gt;0 -->\n",
"<g class=\"edge\" id=\"edge1\">\n",
@ -3478,8 +3481,11 @@
"<!-- 1 -->\n",
"<g class=\"node\" id=\"node3\">\n",
"<title>1</title>\n",
"<g id=\"a_node3\"><a xlink:title=\"0,0\">\n",
"<ellipse cx=\"294\" cy=\"-118\" fill=\"#ffffaa\" rx=\"18\" ry=\"18\" stroke=\"#000000\"/>\n",
"<text fill=\"#000000\" font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"294\" y=\"-114.3\">1</text>\n",
"</a>\n",
"</g>\n",
"</g>\n",
"<!-- 0&#45;&gt;1 -->\n",
"<g class=\"edge\" id=\"edge2\">\n",
@ -3492,8 +3498,11 @@
"<!-- 2 -->\n",
"<g class=\"node\" id=\"node4\">\n",
"<title>2</title>\n",
"<g id=\"a_node4\"><a xlink:title=\"0,1\">\n",
"<ellipse cx=\"190\" cy=\"-118\" fill=\"#ffffaa\" rx=\"18\" ry=\"18\" stroke=\"#000000\"/>\n",
"<text fill=\"#000000\" font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"190\" y=\"-114.3\">2</text>\n",
"</a>\n",
"</g>\n",
"</g>\n",
"<!-- 0&#45;&gt;2 -->\n",
"<g class=\"edge\" id=\"edge3\">\n",
@ -3506,8 +3515,11 @@
"<!-- 3 -->\n",
"<g class=\"node\" id=\"node5\">\n",
"<title>3</title>\n",
"<g id=\"a_node5\"><a xlink:title=\"1,0\">\n",
"<ellipse cx=\"190\" cy=\"-18\" fill=\"#ffffaa\" rx=\"18\" ry=\"18\" stroke=\"#000000\"/>\n",
"<text fill=\"#000000\" font-family=\"Lato\" font-size=\"14.00\" text-anchor=\"middle\" x=\"190\" y=\"-14.3\">3</text>\n",
"</a>\n",
"</g>\n",
"</g>\n",
"<!-- 0&#45;&gt;3 -->\n",
"<g class=\"edge\" id=\"edge4\">\n",
@ -3655,7 +3667,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2053eae0> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec222870> >"
]
},
"metadata": {},
@ -3756,7 +3768,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2055f780> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec2458d0> >"
]
},
"execution_count": 25,
@ -3830,7 +3842,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2056bc30> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec245de0> >"
]
},
"execution_count": 26,
@ -3996,7 +4008,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2056b270> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec251e10> >"
]
},
"execution_count": 28,
@ -4083,7 +4095,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2053eae0> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec222870> >"
]
},
"metadata": {},
@ -4152,7 +4164,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2053eae0> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec222870> >"
]
},
"metadata": {},
@ -4243,7 +4255,7 @@
"</svg>\n"
],
"text/plain": [
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7fde2053eae0> >"
"<spot.impl.twa_graph; proxy of <Swig Object of type 'std::shared_ptr< spot::twa_graph > *' at 0x7f76ec222870> >"
]
},
"execution_count": 30,
@ -4276,7 +4288,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.5rc1"
"version": "3.6.5"
}
},
"nbformat": 4,

File diff suppressed because it is too large Load diff