Commit b11c07b3 authored by Alexandre Duret-Lutz's avatar Alexandre Duret-Lutz

dot: add a <N option

* spot/twaalgos/dot.cc: Implement it.
* spot/taalgos/dot.cc: Ignore it.
* spot/twaalgos/copy.cc, spot/twaalgos/copy.hh: Add option
to limit the number of states.
* tests/python/ltsmin.ipynb: Improve test case.
* tests/Makefile.am: Cleanup the files generated by ltsmin.ipynb.
* python/spot/__init__.py (setup): Add a max_states argument
that default to 50.
* bin/common_aoutput.cc: Mention the <INT option.
* NEWS: Likewise.
parent 4571d6dd
......@@ -12,11 +12,23 @@ New in spot 1.99.7a (not yet released)
object can be queried about the supported variables and their
types.
* print_dot() now accepts an option of the form "<N" to specify
a maximum number of states to output. Incomplete states are
then marked appropriately. For a quick example, compare
ltl2tgba -D 'Ga | Gb | Gc' -d'<3'
with
ltl2tgba -D 'Ga | Gb | Gc' -d
Python:
* The ltsmin interface has been binded in Python. See
https://spot.lrde.epita.fr/ipynb/ltsmin.html for a short example.
* spot.setup() sets de maximum number of states to display in
automata to 50 by default, as more states is likely to be
unreadable (and slow to process by GraphViz). This can be
overridden by calling spot.setup(max_states=N).
Documentation:
* There is a new page giving informal illustrations (and extra
......
......@@ -80,7 +80,7 @@ static const argp_option options[] =
{
/**************************************************/
{ nullptr, 0, nullptr, 0, "Output format:", 3 },
{ "dot", 'd', "1|a|b|B|c|e|f(FONT)|h|n|N|o|r|R|s|t|v|+INT",
{ "dot", 'd', "1|a|b|B|c|e|f(FONT)|h|n|N|o|r|R|s|t|v|+INT|<INT",
OPTION_ARG_OPTIONAL,
"GraphViz's format. Add letters for "
"(1) force numbered states, "
......@@ -93,7 +93,8 @@ static const argp_option options[] =
"(r) rainbow colors for acceptance sets, "
"(R) color acceptance sets by Inf/Fin, (s) with SCCs, "
"(t) force transition-based acceptance, "
"(+INT) add INT to all set numbers", 0 },
"(+INT) add INT to all set numbers, "
"(<INT) display at most INT states", 0 },
{ "hoaf", 'H', "i|l|m|s|t|v", OPTION_ARG_OPTIONAL,
"Output the automaton in HOA format (default). Add letters to select "
"(i) use implicit labels for complete deterministic automata, "
......
......@@ -71,6 +71,8 @@ def setup(**kwargs):
the font to use in the GraphViz output (default: 'Lato')
show_default : str
default options for show()
max_states : int
maximum number of states in GraphViz output (default: 50)
"""
import os
......@@ -80,7 +82,8 @@ def setup(**kwargs):
kwargs.get('fillcolor', '#ffffaa'))
bullets = 'B' if kwargs.get('bullets', True) else ''
d = 'rf({})'.format(kwargs.get('font', 'Lato')) + bullets
max_states = '<' + str(kwargs.get('max_states', 50))
d = 'rf({})'.format(kwargs.get('font', 'Lato')) + bullets + max_states
global _show_default
_show_default = kwargs.get('show_default', None)
os.environ['SPOT_DOTDEFAULT'] = d
......
// -*- coding: utf-8 -*-
// Copyright (C) 2010, 2012, 2014, 2015 Laboratoire de Recherche et
// Developpement de l Epita (LRDE).
// Copyright (C) 2010, 2012, 2014, 2015, 2016 Laboratoire de Recherche
// et Developpement de l Epita (LRDE).
//
// This file is part of Spot, a model checking library.
//
......@@ -84,7 +84,16 @@ namespace spot
case 'v':
opt_horizontal_ = false;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'a':
case 'b':
case 'B':
......@@ -96,6 +105,8 @@ namespace spot
case 'R':
case 's':
case 't':
case '+':
case '<':
// All these options are implemented by dotty() on TGBA,
// but are not implemented here. We simply ignore them,
// because raising an exception if they are in
......
......@@ -27,13 +27,15 @@
namespace spot
{
twa_graph_ptr
copy(const const_twa_ptr& aut, twa::prop_set p, bool preserve_names)
copy(const const_twa_ptr& aut, twa::prop_set p,
bool preserve_names, unsigned max_states)
{
twa_graph_ptr out = make_twa_graph(aut->get_dict());
out->copy_acceptance_of(aut);
out->copy_ap_of(aut);
out->prop_copy(aut, p);
std::vector<std::string>* names = nullptr;
std::set<unsigned>* incomplete = nullptr;
if (preserve_names)
{
names = new std::vector<std::string>;
......@@ -69,9 +71,27 @@ namespace spot
unsigned src2;
std::tie(src1, src2) = *todo.front();
todo.pop_front();
for (auto* t: aut->succ(src1))
out->new_edge(src2, new_state(t->dst()), t->cond(), t->acc());
{
if (SPOT_UNLIKELY(max_states < out->num_states()))
{
// If we have reached the max number of state, never try
// to create a new one.
auto i = seen.find(t->dst());
if (i == seen.end())
{
if (!incomplete)
incomplete = new std::set<unsigned>;
incomplete->insert(src2);
continue;
}
out->new_edge(src2, i->second, t->cond(), t->acc());
}
else
{
out->new_edge(src2, new_state(t->dst()), t->cond(), t->acc());
}
}
}
......@@ -84,6 +104,8 @@ namespace spot
ptr->destroy();
}
if (incomplete)
out->set_named_prop("incomplete-states", incomplete);
return out;
}
}
......@@ -33,5 +33,6 @@ namespace spot
///
/// This works for using the abstract interface for automata
SPOT_API twa_graph_ptr
copy(const const_twa_ptr& aut, twa::prop_set p, bool preserve_names = false);
copy(const const_twa_ptr& aut, twa::prop_set p,
bool preserve_names = false, unsigned max_states = -1U);
}
......@@ -57,6 +57,7 @@ namespace spot
const_twa_graph_ptr aut_;
std::vector<std::string>* sn_ = nullptr;
std::vector<std::pair<unsigned, unsigned>>* sprod_ = nullptr;
std::set<unsigned>* incomplete_;
std::string* name_ = nullptr;
acc_cond::mark_t inf_sets_ = 0U;
acc_cond::mark_t fin_sets_ = 0U;
......@@ -83,9 +84,21 @@ namespace spot
};
const char*const* palette = palette9;
int palette_mod = 9;
unsigned max_states_ = -1U;
bool max_states_given_ = false;
public:
unsigned max_states()
{
return max_states_;
}
bool max_states_given()
{
return max_states_given_;
}
void
parse_opts(const char* options)
{
......@@ -95,7 +108,7 @@ namespace spot
{
case '.':
{
// Copy the value in a string, so future calls to
// Copy the value in a string, so future calls to
// parse_opts do not fail if the environment has
// changed. (This matters particularly in an ipython
// notebook, where it is tempting to redefine
......@@ -123,6 +136,25 @@ namespace spot
options = end;
break;
}
case '<':
{
char* end;
max_states_ = strtoul(options, &end, 10);
if (options == end)
throw std::runtime_error
("missing number after '<' in print_dot() options");
if (max_states_ == 0)
{
max_states_ = -1U;
max_states_given_ = false;
}
else
{
max_states_given_ = true;
}
options = end;
break;
}
case '1':
opt_want_state_names_ = false;
break;
......@@ -445,6 +477,9 @@ namespace spot
os_ << ", peripheries=2";
os_ << "]\n";
}
if (incomplete_ && incomplete_->find(s) != incomplete_->end())
os_ << " u" << s << " [label=\"...\", shape=none, width=0, height=0"
"]\n " << s << " -> u" << s << " [style=dashed]\n";
}
void
......@@ -497,6 +532,8 @@ namespace spot
sprod_ = nullptr;
}
}
incomplete_ =
aut->get_named_prop<std::set<unsigned>>("incomplete-states");
if (opt_name_)
name_ = aut_->get_named_prop<std::string>("automaton-name");
mark_states_ = (!opt_force_acc_trans_
......@@ -566,8 +603,8 @@ namespace spot
{
dotty_output d(os, options);
auto aut = std::dynamic_pointer_cast<const twa_graph>(g);
if (!aut)
aut = copy(g, twa::prop_set::all(), true);
if (!aut || (d.max_states_given() && aut->num_states() >= d.max_states()))
aut = copy(g, twa::prop_set::all(), true, d.max_states() - 1);
d.print(aut);
return os;
}
......
......@@ -316,7 +316,7 @@ TESTS_python = \
python/trival.py
endif
CLEANFILES = python/finite.dve2C python/finite.dve.cpp
CLEANFILES = python/test1.dve python/test1.dve2C python/test1.dve.cpp
SUFFIXES = .ipynb .html
.ipynb.html:
......
This diff is collapsed.
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