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.
This commit is contained in:
parent
4571d6dd3a
commit
b11c07b351
9 changed files with 1145 additions and 364 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue