dotty: colored acceptance sets
This implement several new options for --dot in order to allow emptiness sets to be output as colored ⓿ or ❶... Also add a SPOT_DOTDEFAULT environment variable. * NEWS, src/bin/man/spot-x.x, src/bin/common_aoutput.cc, src/bin/dstar2tgba.cc: Document the new options. * doc/org/.dir-locals.el, doc/org/init.el.in: Setup SPOT_DOTEXTRA and SPOT_DOTDEFAULT for all documents. * doc/org/autfilt.org, doc/org/dstar2tgba.org, doc/org/ltl2tgba.org, doc/org/ltldo.org, doc/org/oaut.org, doc/org/randaut.org, doc/org/satmin.org: Adjust to this new setup. * src/misc/escape.cc, src/misc/escape.hh (escape_html): New function. * src/tgba/acc.cc, src/tgba/acc.hh (to_text, to_html): New method. * src/tgbaalgos/dotty.cc: Implement the new options. * src/tgbatest/readsave.test, wrap/python/tests/automata.ipynb: More tests. * wrap/python/spot.py: Make sure the default argument for dotty_reachable is None, so that SPOT_DOTDEFAULT is honored.
This commit is contained in:
parent
7caf2b83d6
commit
838bfb2ae3
21 changed files with 1500 additions and 1193 deletions
|
|
@ -51,10 +51,13 @@ static const argp_option options[] =
|
|||
{
|
||||
/**************************************************/
|
||||
{ 0, 0, 0, 0, "Output format:", 3 },
|
||||
{ "dot", OPT_DOT, "a|c|h|n|N|s|t|v", OPTION_ARG_OPTIONAL,
|
||||
{ "dot", OPT_DOT, "a|b|c|f(FONT)|h|n|N|r|R|s|t|v", OPTION_ARG_OPTIONAL,
|
||||
"GraphViz's format (default). Add letters for "
|
||||
"(a) acceptance display, (c) circular nodes, (h) horizontal layout, "
|
||||
"(v) vertical layout, (n) with name, (N) without name, (s) with SCCs, "
|
||||
"(a) acceptance display, (b) acceptance sets as bullets,"
|
||||
"(c) circular nodes, (f(FONT)) use FONT, (h) horizontal layout, "
|
||||
"(v) vertical layout, (n) with name, (N) without name, "
|
||||
"(r) rainbow colors for acceptance set, "
|
||||
"(R) color acceptance set by Inf/Fin, (s) with SCCs, "
|
||||
"(t) force transition-based acceptance.", 0 },
|
||||
{ "hoaf", 'H', "i|s|t|m|l", OPTION_ARG_OPTIONAL,
|
||||
"Output the automaton in HOA format. Add letters to select "
|
||||
|
|
|
|||
|
|
@ -73,10 +73,13 @@ static const argp_option options[] =
|
|||
"of the given property)", 0 },
|
||||
/**************************************************/
|
||||
{ 0, 0, 0, 0, "Output format:", 3 },
|
||||
{ "dot", OPT_DOT, "a|c|h|n|N|s|t|v", OPTION_ARG_OPTIONAL,
|
||||
"GraphViz's format (default). Add letters for (a) acceptance display, "
|
||||
"(c) circular nodes, (h) horizontal layout, (v) vertical layout, "
|
||||
"(n) with name, (N) without name, (s) with SCCs, "
|
||||
{ "dot", OPT_DOT, "a|b|c|f(FONT)|h|n|N|r|R|s|t|v", OPTION_ARG_OPTIONAL,
|
||||
"GraphViz's format (default). Add letters for "
|
||||
"(a) acceptance display, (b) acceptance sets as bullets,"
|
||||
"(c) circular nodes, (f(FONT)) use FONT, (h) horizontal layout, "
|
||||
"(v) vertical layout, (n) with name, (N) without name, "
|
||||
"(r) rainbow colors for acceptance set, "
|
||||
"(R) color acceptance set by Inf/Fin, (s) with SCCs, "
|
||||
"(t) force transition-based acceptance.", 0 },
|
||||
{ "hoaf", 'H', "i|s|t|m|l", OPTION_ARG_OPTIONAL,
|
||||
"Output the automaton in HOA format. Add letters to select "
|
||||
|
|
|
|||
|
|
@ -11,6 +11,15 @@ spot-x \- Common fine-tuning options.
|
|||
|
||||
[ENVIRONMENT VARIABLES]
|
||||
|
||||
.TP
|
||||
\fBSPOT_DOTDEFAULT\fR
|
||||
Whenever the \f(CW--dot\fR option is used without argument (even
|
||||
implicitely), the contents of this variable is used as default
|
||||
argument. If you have some default setting in \fBSPOT_DOTDEFAULT\fR
|
||||
but want to alter them temporarily for one call, use
|
||||
\f(CW--dot=.yyy\fR: the dot character will be replaced by the contents
|
||||
of the \f(CWSPOT_DOTDEFAULT\fR environment variable.
|
||||
|
||||
.TP
|
||||
\fBSPOT_DOTEXTRA\fR
|
||||
The contents of this variable is added to any dot output, immediately
|
||||
|
|
|
|||
|
|
@ -77,6 +77,31 @@ namespace spot
|
|||
return os;
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
escape_html(std::ostream& os, const std::string& str)
|
||||
{
|
||||
for (auto i: str)
|
||||
switch (i)
|
||||
{
|
||||
case '&':
|
||||
os << "&";
|
||||
break;
|
||||
case '"':
|
||||
os << """;
|
||||
break;
|
||||
case '<':
|
||||
os << "<";
|
||||
break;
|
||||
case '>':
|
||||
os << ">";
|
||||
break;
|
||||
default:
|
||||
os << i;
|
||||
break;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
escape_str(std::ostream& os, const std::string& str)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -46,6 +46,13 @@ namespace spot
|
|||
SPOT_API std::ostream&
|
||||
escape_latex(std::ostream& os, const std::string& str);
|
||||
|
||||
/// \brief Escape special HTML characters.
|
||||
///
|
||||
/// The following characters are rewritten:
|
||||
/// <code>> < " &</code>
|
||||
SPOT_API std::ostream&
|
||||
escape_html(std::ostream& os, const std::string& str);
|
||||
|
||||
/// \brief Escape characters <code>"</code>, <code>\\</code>, and
|
||||
/// <code>\\n</code> in \a str.
|
||||
SPOT_API std::ostream&
|
||||
|
|
|
|||
|
|
@ -48,9 +48,16 @@ namespace spot
|
|||
|
||||
namespace
|
||||
{
|
||||
void default_set_printer(std::ostream& os, int v)
|
||||
{
|
||||
os << v;
|
||||
}
|
||||
|
||||
template<bool html>
|
||||
static void
|
||||
print_code(std::ostream& os,
|
||||
const acc_cond::acc_code& code, unsigned pos)
|
||||
const acc_cond::acc_code& code, unsigned pos,
|
||||
std::function<void(std::ostream&, int)> set_printer)
|
||||
{
|
||||
const char* op = " | ";
|
||||
auto& w = code[pos];
|
||||
|
|
@ -59,7 +66,7 @@ namespace spot
|
|||
switch (w.op)
|
||||
{
|
||||
case acc_cond::acc_op::And:
|
||||
op = " & ";
|
||||
op = html ? " & " : " & ";
|
||||
case acc_cond::acc_op::Or:
|
||||
{
|
||||
unsigned sub = pos - w.size;
|
||||
|
|
@ -73,7 +80,7 @@ namespace spot
|
|||
first = false;
|
||||
else
|
||||
os << op;
|
||||
print_code(os, code, pos);
|
||||
print_code<html>(os, code, pos, set_printer);
|
||||
pos -= code[pos].size;
|
||||
}
|
||||
if (!top)
|
||||
|
|
@ -102,8 +109,10 @@ namespace spot
|
|||
{
|
||||
if (a & 1)
|
||||
{
|
||||
os << and_ << "Inf(" << negated << level << ')';
|
||||
and_ = "&";
|
||||
os << and_ << "Inf(" << negated;
|
||||
set_printer(os, level);
|
||||
os << ')';
|
||||
and_ = html ? "&" : "&";
|
||||
}
|
||||
a >>= 1;
|
||||
++level;
|
||||
|
|
@ -135,7 +144,9 @@ namespace spot
|
|||
{
|
||||
if (a & 1)
|
||||
{
|
||||
os << or_ << "Fin(" << negated << level << ')';
|
||||
os << or_ << "Fin(" << negated;
|
||||
set_printer(os, level);
|
||||
os << ')';
|
||||
or_ = "|";
|
||||
}
|
||||
a >>= 1;
|
||||
|
|
@ -746,13 +757,69 @@ namespace spot
|
|||
return used_in_cond;
|
||||
}
|
||||
|
||||
std::pair<acc_cond::mark_t, acc_cond::mark_t>
|
||||
acc_cond::acc_code::used_inf_fin_sets() const
|
||||
{
|
||||
if (is_true() || is_false())
|
||||
return {0U, 0U};
|
||||
|
||||
acc_cond::mark_t used_fin = 0U;
|
||||
acc_cond::mark_t used_inf = 0U;
|
||||
auto pos = &back();
|
||||
auto end = &front();
|
||||
while (pos > end)
|
||||
{
|
||||
switch (pos->op)
|
||||
{
|
||||
case acc_cond::acc_op::And:
|
||||
case acc_cond::acc_op::Or:
|
||||
--pos;
|
||||
break;
|
||||
case acc_cond::acc_op::Fin:
|
||||
case acc_cond::acc_op::FinNeg:
|
||||
used_fin |= pos[-1].mark;
|
||||
pos -= 2;
|
||||
break;
|
||||
case acc_cond::acc_op::Inf:
|
||||
case acc_cond::acc_op::InfNeg:
|
||||
used_inf |= pos[-1].mark;
|
||||
pos -= 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {used_inf, used_fin};
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
acc_cond::acc_code::to_html(std::ostream& os,
|
||||
std::function<void(std::ostream&, int)>
|
||||
set_printer) const
|
||||
{
|
||||
if (empty())
|
||||
os << 't';
|
||||
else
|
||||
print_code<true>(os, *this, size() - 1,
|
||||
set_printer ? set_printer : default_set_printer);
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
acc_cond::acc_code::to_text(std::ostream& os,
|
||||
std::function<void(std::ostream&, int)>
|
||||
set_printer) const
|
||||
{
|
||||
if (empty())
|
||||
os << 't';
|
||||
else
|
||||
print_code<false>(os, *this, size() - 1,
|
||||
set_printer ? set_printer : default_set_printer);
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const spot::acc_cond::acc_code& code)
|
||||
{
|
||||
if (code.empty())
|
||||
os << 't';
|
||||
else
|
||||
print_code(os, code, code.size() - 1);
|
||||
return os;
|
||||
return code.to_text(os);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -660,6 +660,24 @@ namespace spot
|
|||
// Return the set of sets appearing in the condition.
|
||||
acc_cond::mark_t used_sets() const;
|
||||
|
||||
// Return the sets used as Inf or Fin in the acceptance condition
|
||||
std::pair<acc_cond::mark_t, acc_cond::mark_t> used_inf_fin_sets() const;
|
||||
|
||||
// Print the acceptance as HTML. The set_printer function can
|
||||
// be used to implement customized output for set numbers.
|
||||
std::ostream&
|
||||
to_html(std::ostream& os,
|
||||
std::function<void(std::ostream&, int)>
|
||||
set_printer = nullptr) const;
|
||||
|
||||
// Print the acceptance as text. The set_printer function can
|
||||
// be used to implement customized output for set numbers.
|
||||
std::ostream&
|
||||
to_text(std::ostream& os,
|
||||
std::function<void(std::ostream&, int)>
|
||||
set_printer = nullptr) const;
|
||||
|
||||
// Calls to_text
|
||||
SPOT_API
|
||||
friend std::ostream& operator<<(std::ostream& os, const acc_code& code);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,11 +31,16 @@
|
|||
#include "tgba/formula2bdd.hh"
|
||||
#include "tgbaalgos/sccinfo.hh"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
namespace spot
|
||||
{
|
||||
namespace
|
||||
{
|
||||
constexpr int MAX_BULLET = 20;
|
||||
|
||||
class dotty_output
|
||||
{
|
||||
std::ostream& os_;
|
||||
|
|
@ -46,74 +51,229 @@ namespace spot
|
|||
bool opt_show_acc_ = false;
|
||||
bool mark_states_ = false;
|
||||
bool opt_scc_ = false;
|
||||
bool opt_html_labels_ = false;
|
||||
const_tgba_digraph_ptr aut_;
|
||||
std::vector<std::string>* sn_;
|
||||
std::string* name_ = nullptr;
|
||||
acc_cond::mark_t inf_sets_ = 0U;
|
||||
acc_cond::mark_t fin_sets_ = 0U;
|
||||
bool opt_rainbow = false;
|
||||
bool opt_bullet = false;
|
||||
bool opt_all_bullets = false;
|
||||
std::string opt_font_;
|
||||
|
||||
const char* const palette9[9] =
|
||||
{
|
||||
"#5DA5DA", /* blue */
|
||||
"#F17CB0", /* pink */
|
||||
"#FAA43A", /* orange */
|
||||
"#B276B2", /* purple */
|
||||
"#60BD68", /* green */
|
||||
"#F15854", /* red */
|
||||
"#B2912F", /* brown */
|
||||
"#4D4D4D", /* gray */
|
||||
"#DECF3F", /* yellow */
|
||||
};
|
||||
const char*const* palette = palette9;
|
||||
int palette_mod = 9;
|
||||
|
||||
public:
|
||||
|
||||
void
|
||||
parse_opts(const char* options)
|
||||
{
|
||||
const char* orig = options;
|
||||
while (char c = *options++)
|
||||
switch (c)
|
||||
{
|
||||
case '.':
|
||||
{
|
||||
static const char* def = getenv("SPOT_DOTDEFAULT");
|
||||
// Prevent infinite recursions...
|
||||
if (orig == def)
|
||||
throw std::runtime_error
|
||||
(std::string("SPOT_DOTDEFAULT should not contain '.'"));
|
||||
if (def)
|
||||
parse_opts(def);
|
||||
break;
|
||||
}
|
||||
case 'a':
|
||||
opt_show_acc_ = true;
|
||||
break;
|
||||
case 'b':
|
||||
opt_bullet = true;
|
||||
break;
|
||||
case 'c':
|
||||
opt_circles_ = true;
|
||||
break;
|
||||
case 'h':
|
||||
opt_horizontal_ = true;
|
||||
break;
|
||||
case 'f':
|
||||
if (*options != '(')
|
||||
throw std::runtime_error
|
||||
(std::string("invalid font specification for dotty()"));
|
||||
{
|
||||
auto* end = strchr(++options, ')');
|
||||
if (!end)
|
||||
throw std::runtime_error
|
||||
(std::string("invalid font specification for dotty()"));
|
||||
opt_font_ = std::string(options, end - options);
|
||||
options = end + 1;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
opt_name_ = true;
|
||||
break;
|
||||
case 'N':
|
||||
opt_name_ = false;
|
||||
break;
|
||||
case 'r':
|
||||
opt_html_labels_ = true;
|
||||
opt_rainbow = true;
|
||||
break;
|
||||
case 'R':
|
||||
opt_html_labels_ = true;
|
||||
opt_rainbow = false;
|
||||
break;
|
||||
case 's':
|
||||
opt_scc_ = true;
|
||||
break;
|
||||
case 'v':
|
||||
opt_horizontal_ = false;
|
||||
break;
|
||||
case 't':
|
||||
opt_force_acc_trans_ = true;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error
|
||||
(std::string("unknown option for dotty(): ") + c);
|
||||
}
|
||||
}
|
||||
|
||||
dotty_output(std::ostream& os, const char* options)
|
||||
: os_(os)
|
||||
{
|
||||
if (options)
|
||||
while (char c = *options++)
|
||||
switch (c)
|
||||
{
|
||||
case 'a':
|
||||
opt_show_acc_ = true;
|
||||
break;
|
||||
case 'c':
|
||||
opt_circles_ = true;
|
||||
break;
|
||||
case 'h':
|
||||
opt_horizontal_ = true;
|
||||
break;
|
||||
case 'n':
|
||||
opt_name_ = true;
|
||||
break;
|
||||
case 'N':
|
||||
opt_name_ = false;
|
||||
break;
|
||||
case 's':
|
||||
opt_scc_ = true;
|
||||
break;
|
||||
case 'v':
|
||||
opt_horizontal_ = false;
|
||||
break;
|
||||
case 't':
|
||||
opt_force_acc_trans_ = true;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error
|
||||
(std::string("unknown option for dotty(): ") + c);
|
||||
}
|
||||
parse_opts(options ? options : ".");
|
||||
}
|
||||
|
||||
void
|
||||
output_set(std::ostream& os, int v) const
|
||||
{
|
||||
if (opt_bullet && (v >= 0) & (v <= MAX_BULLET))
|
||||
{
|
||||
static const char* const tab[MAX_BULLET + 1] = {
|
||||
"⓿", "❶", "❷", "❸",
|
||||
"❹", "❺", "❻", "❼",
|
||||
"❽", "❾", "❿", "⓫",
|
||||
"⓬", "⓭", "⓮", "⓯",
|
||||
"⓰", "⓱", "⓲", "⓳",
|
||||
"⓴",
|
||||
};
|
||||
os << tab[v];
|
||||
}
|
||||
else
|
||||
{
|
||||
os << v;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
html_set_color(int v) const
|
||||
{
|
||||
if (opt_rainbow)
|
||||
return palette[v % palette_mod];
|
||||
// Color according to Fin/Inf
|
||||
if (inf_sets_.has(v))
|
||||
{
|
||||
if (fin_sets_.has(v))
|
||||
return palette[2];
|
||||
else
|
||||
return palette[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return palette[1];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
output_html_set_aux(std::ostream& os, int v) const
|
||||
{
|
||||
os << "<font color=\"" << html_set_color(v) << "\">";
|
||||
output_set(os, v);
|
||||
os << "</font>";
|
||||
}
|
||||
|
||||
void
|
||||
output_html_set(int v) const
|
||||
{
|
||||
output_html_set_aux(os_, v);
|
||||
}
|
||||
|
||||
void
|
||||
start()
|
||||
{
|
||||
if (opt_html_labels_)
|
||||
std::tie(inf_sets_, fin_sets_) =
|
||||
aut_->get_acceptance().used_inf_fin_sets();
|
||||
if (opt_bullet && aut_->acc().num_sets() <= MAX_BULLET)
|
||||
opt_all_bullets = true;
|
||||
|
||||
os_ << "digraph G {\n";
|
||||
if (opt_horizontal_)
|
||||
os_ << " rankdir=LR\n";
|
||||
if (name_ || opt_show_acc_)
|
||||
{
|
||||
os_ << " label=\"";
|
||||
if (name_)
|
||||
if (!opt_html_labels_)
|
||||
{
|
||||
escape_str(os_, *name_);
|
||||
os_ << " label=\"";
|
||||
if (name_)
|
||||
{
|
||||
escape_str(os_, *name_);
|
||||
if (opt_show_acc_)
|
||||
os_ << "\\n";
|
||||
}
|
||||
if (opt_show_acc_)
|
||||
os_ << "\\n";
|
||||
aut_->get_acceptance().to_text
|
||||
(os_, [this](std::ostream& os, int v)
|
||||
{
|
||||
this->output_set(os, v);
|
||||
});
|
||||
os_ << "\"\n";
|
||||
}
|
||||
if (opt_show_acc_)
|
||||
os_ << aut_->get_acceptance();
|
||||
os_ << "\"\n labelloc=\"t\"\n";
|
||||
else
|
||||
{
|
||||
os_ << " label=<";
|
||||
if (name_)
|
||||
{
|
||||
escape_html(os_, *name_);
|
||||
if (opt_show_acc_)
|
||||
os_ << "<br/>";
|
||||
}
|
||||
if (opt_show_acc_)
|
||||
aut_->get_acceptance().to_html
|
||||
(os_, [this](std::ostream& os, int v)
|
||||
{
|
||||
this->output_html_set_aux(os, v);
|
||||
});
|
||||
os_ << ">\n";
|
||||
}
|
||||
os_ << " labelloc=\"t\"\n";
|
||||
}
|
||||
if (opt_circles_)
|
||||
os_ << " node [shape=\"circle\"]\n";
|
||||
if (!opt_font_.empty())
|
||||
os_ << " fontname=\"" << opt_font_
|
||||
<< "\"\n node [fontname=\"" << opt_font_
|
||||
<< "\"]\n edge [fontname=\"" << opt_font_
|
||||
<< "\"]\n";
|
||||
// Any extra text passed in the SPOT_DOTEXTRA environment
|
||||
// variable should be output at the end of the "header", so
|
||||
// that our setup can be overridden.
|
||||
static const char* extra = getenv("SPOT_DOTEXTRA");
|
||||
if (extra)
|
||||
if (extra && *extra)
|
||||
os_ << " " << extra << '\n';
|
||||
os_ << " I [label=\"\", style=invis, ";
|
||||
os_ << (opt_horizontal_ ? "width" : "height");
|
||||
|
|
@ -144,15 +304,53 @@ namespace spot
|
|||
process_link(const tgba_digraph::trans_storage_t& t)
|
||||
{
|
||||
std::string label = bdd_format_formula(aut_->get_dict(), t.cond);
|
||||
label = escape_str(label);
|
||||
if (!mark_states_)
|
||||
if (auto a = t.acc)
|
||||
{
|
||||
label += "\\n";
|
||||
label += aut_->acc().format(a);
|
||||
}
|
||||
os_ << " " << t.src << " -> " << t.dst
|
||||
<< " [label=\"" + label + "\"]\n";
|
||||
os_ << " " << t.src << " -> " << t.dst;
|
||||
if (!opt_html_labels_)
|
||||
{
|
||||
os_ << " [label=\"";
|
||||
escape_str(os_, label);
|
||||
if (!mark_states_)
|
||||
if (auto a = t.acc)
|
||||
{
|
||||
os_ << "\\n";
|
||||
if (!opt_all_bullets)
|
||||
os_ << '{';
|
||||
const char* space = "";
|
||||
for (auto v: a.sets())
|
||||
{
|
||||
if (!opt_all_bullets)
|
||||
os_ << space;
|
||||
output_set(os_, v);
|
||||
space = ",";
|
||||
}
|
||||
if (!opt_all_bullets)
|
||||
os_ << '}';
|
||||
}
|
||||
os_ << "\"]\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
os_ << " [label=<";
|
||||
escape_html(os_, label);
|
||||
if (!mark_states_)
|
||||
if (auto a = t.acc)
|
||||
{
|
||||
os_ << "<br/>";
|
||||
if (!opt_all_bullets)
|
||||
os_ << '{';
|
||||
const char* space = "";
|
||||
for (auto v: a.sets())
|
||||
{
|
||||
if (!opt_all_bullets)
|
||||
os_ << space;
|
||||
output_html_set(v);
|
||||
space = ",";
|
||||
}
|
||||
if (!opt_all_bullets)
|
||||
os_ << '}';
|
||||
}
|
||||
os_ << ">]\n";
|
||||
}
|
||||
}
|
||||
|
||||
void print(const const_tgba_digraph_ptr& aut)
|
||||
|
|
|
|||
|
|
@ -308,7 +308,7 @@ State: 3 "s3"
|
|||
EOF
|
||||
|
||||
$autfilt -H input |
|
||||
SPOT_DOTEXTRA='/* hello world */' $autfilt --dot=vcsn >output
|
||||
SPOT_DOTDEFAULT=vcsn SPOT_DOTEXTRA='/* hello world */' $autfilt >output
|
||||
|
||||
cat >expected <<EOF
|
||||
digraph G {
|
||||
|
|
@ -360,20 +360,46 @@ digraph G {
|
|||
EOF
|
||||
diff output expected
|
||||
|
||||
$ltl2tgba --dot=an 'GFa & GFb' >output
|
||||
$ltl2tgba --dot=ban 'GFa & GFb' >output
|
||||
cat output
|
||||
cat >expected <<EOF
|
||||
digraph G {
|
||||
rankdir=LR
|
||||
label="G(Fa & Fb)\\nInf(0)&Inf(1)"
|
||||
label="G(Fa & Fb)\nInf(⓿)&Inf(❶)"
|
||||
labelloc="t"
|
||||
I [label="", style=invis, width=0]
|
||||
I -> 0
|
||||
0 [label="0"]
|
||||
0 -> 0 [label="a & b\n{0,1}"]
|
||||
0 -> 0 [label="a & b\n⓿❶"]
|
||||
0 -> 0 [label="!a & !b"]
|
||||
0 -> 0 [label="!a & b\n{1}"]
|
||||
0 -> 0 [label="a & !b\n{0}"]
|
||||
0 -> 0 [label="!a & b\n❶"]
|
||||
0 -> 0 [label="a & !b\n⓿"]
|
||||
}
|
||||
EOF
|
||||
diff output expected
|
||||
|
||||
|
||||
SPOT_DOTDEFAULT=bra $ltl2tgba --dot='c.f(Lato)' 'GFa & GFb' >output
|
||||
cat output
|
||||
|
||||
zero='<font color="#5DA5DA">⓿</font>'
|
||||
one='<font color="#F17CB0">❶</font>'
|
||||
cat >expected <<EOF
|
||||
digraph G {
|
||||
rankdir=LR
|
||||
label=<Inf($zero)&Inf($one)>
|
||||
labelloc="t"
|
||||
node [shape="circle"]
|
||||
fontname="Lato"
|
||||
node [fontname="Lato"]
|
||||
edge [fontname="Lato"]
|
||||
I [label="", style=invis, width=0]
|
||||
I -> 0
|
||||
0 [label="0"]
|
||||
0 -> 0 [label=<a & b<br/>$zero$one>]
|
||||
0 -> 0 [label=<!a & !b>]
|
||||
0 -> 0 [label=<!a & b<br/>$one>]
|
||||
0 -> 0 [label=<a & !b<br/>$zero>]
|
||||
}
|
||||
EOF
|
||||
diff output expected
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue