mCRL2
Loading...
Searching...
No Matches
liblts_aut.cpp
Go to the documentation of this file.
1// Author(s): Muck van Weerdenburg, Jan Friso Groote
2// Copyright: see the accompanying file COPYING or copy at
3// https://github.com/mCRL2org/mCRL2/blob/master/COPYING
4//
5// Distributed under the Boost Software License, Version 1.0.
6// (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8//
10
11#include <fstream>
13#include "mcrl2/lts/lts_aut.h"
15
16
17using namespace mcrl2::lts;
18
19static void read_newline(std::istream& is, const std::size_t line_no)
20{
21 char ch;
22 is.get(ch);
23
24 // Skip over spaces
25 while (ch == ' ')
26 {
27 is.get(ch);
28 }
29
30 // Windows systems typically have a carriage return before a newline.
31 if (ch == '\r')
32 {
33 is.get(ch);
34 }
35
36 if (ch != '\n' && !is.eof()) // Last line does not need to be terminated with an eoln.
37 {
38 if (line_no==1)
39 {
40 throw mcrl2::runtime_error("Expect a newline after the header des(...,...,...).");
41 }
42 else
43 {
44 throw mcrl2::runtime_error("Expect a newline after the transition at line " + std::to_string(line_no) + ".");
45 }
46 }
47}
48
49// reads a number, puts it in s, and reads one extra character, which must be either a space or a closing bracket.
50static void read_natural_number_to_string(std::istream& is, std::string& s, const std::size_t line_no)
51{
52 assert(s.empty());
53 char ch;
54 is >> std::skipws >> ch;
55 for( ; isdigit(ch) ; is.get(ch))
56 {
57 s.push_back(ch);
58 }
59 is.putback(ch);
60 if (s.empty())
61 {
62 throw mcrl2::runtime_error("Expect a number at line " + std::to_string(line_no) + ".");
63 }
64}
65
66template <class AUT_LTS_TYPE>
67static std::size_t find_label_index(const std::string& s, mcrl2::utilities::unordered_map < action_label_string, std::size_t >& labs, AUT_LTS_TYPE& l)
68{
69 std::size_t label;
70
71 assert(labs.at(action_label_string::tau_action())==0);
74 if (i==labs.end())
75 {
76 label=l.add_action(as);
77 labs[as]=label;
78 }
79 else
80 {
81 label=i->second;
82 }
83 return label;
84}
85
86static void check_state(std::size_t state, std::size_t number_of_states, std::size_t line_no)
87{
88 if (state>=number_of_states)
89 {
90 throw mcrl2::runtime_error("The state number " + std::to_string(state) + " is not below the number of states (" +
91 std::to_string(number_of_states) + "). Found at line " + std::to_string(line_no) + ".");
92 }
93}
94
96 std::size_t number_of_states, std::size_t line_no)
97{
98 if (probability_state.size()<=1) // This is a simple probabilistic state.
99 {
100 check_state(probability_state.get(), number_of_states, line_no);
101 }
102 else // The state consists of a vector of states and probability pairs.
103 {
105 {
106 check_state(p.state(), number_of_states, line_no);
107 }
108 }
109}
110
111// This procedure tries to read states, indicated by numbers
112// with in between fractions of the shape number/number. The
113// last state number is put in state. The remainder as pairs
114// in the vector. Typical expected input is 3 2/3 4 1/6 78 1/6 3.
116 std::istream& is,
118 const std::size_t line_no)
119{
120 assert(result.size()==0);
121
122 std::size_t state;
123
124 is >> std::skipws >> state;
125
126 if (!is.good())
127 {
128 throw mcrl2::runtime_error("Expect a state number at line " + std::to_string(line_no) + ".");
129 }
130
131 // Check whether the next character is a digit. If so a probability follows.
132 char ch;
133 is >> std::skipws >> ch;
134 is.putback(ch);
135
136 if (!isdigit(ch))
137 {
138 // There is only a single state.
139 result.set(state);
140 return;
141 }
142 bool ready=false;
143
145 while (is.good() && !ready)
146 {
147 // Now read a probabilities followed by the next state.
148 std::string enumerator;
149 read_natural_number_to_string(is,enumerator,line_no);
150 char ch;
151 is >> std::skipws >> ch;
152 if (ch != '/')
153 {
154 throw mcrl2::runtime_error("Expect a / in a probability at line " + std::to_string(line_no) + ".");
155 }
156
157 std::string denominator;
158 read_natural_number_to_string(is,denominator,line_no);
160 remainder=remainder-frac;
161 result.add(state, frac);
162
163 is >> std::skipws >> state;
164
165 if (!is.good())
166 {
167 throw mcrl2::runtime_error("Expect a state number at line " + std::to_string(line_no) + ".");
168 }
169
170 // Check whether the next character is a digit.
171
172 is >> std::skipws >> ch;
173 is.putback(ch);
174
175 if (!isdigit(ch))
176 {
177 ready=true;
178 }
179 }
180
181 result.add(state, remainder);
182}
183
184
185static void read_aut_header(
186 std::istream& is,
188 std::size_t& num_transitions,
189 std::size_t& num_states)
190{
191 std::string s;
192 is.width(3);
193 is >> std::skipws >> s;
194
195 if (s!="des")
196 {
197 throw mcrl2::runtime_error("Expect an .aut file to start with 'des'.");
198 }
199
200 char ch;
201 is >> std::skipws >> ch;
202
203 if (ch != '(')
204 {
205 throw mcrl2::runtime_error("Expect an opening bracket '(' after 'des' in the first line of a .aut file.");
206 }
207
208 read_probabilistic_state(is,initial_state,1);
209
210 is >> std::skipws >> ch;
211 if (ch != ',')
212 {
213 throw mcrl2::runtime_error("Expect a comma after the first number in the first line of a .aut file.");
214 }
215
216 is >> std::skipws >> num_transitions;
217
218 is >> std::skipws >> ch;
219 if (ch != ',')
220 {
221 throw mcrl2::runtime_error("Expect a comma after the second number in the first line of a .aut file.");
222 }
223
224 is >> std::skipws >> num_states;
225
226 is >> ch;
227
228 if (ch != ')')
229 {
230 throw mcrl2::runtime_error("Expect a closing bracket ')' after the third number in the first line of a .aut file.");
231 }
232
233 read_newline(is,1);
234}
235
237 std::istream& is,
238 std::size_t& from,
239 std::string& label,
240 const std::size_t line_no)
241{
242 char ch;
243 is >> std::skipws >> ch;
244 if (is.eof())
245 {
246 return false;
247 }
248 if (ch == 0x04) // found EOT character that separates two files
249 {
250 return false;
251 }
252
253 is >> std::skipws >> from;
254
255 is >> std::skipws >> ch;
256 if (ch != ',')
257 {
258 throw mcrl2::runtime_error("Expect that the first number is followed by a comma at line " + std::to_string(line_no) + ".");
259 }
260
261 is >> std::skipws >> ch;
262 if (ch == '"')
263 {
264 label="";
265 // In case the label is using quotes whitespaces
266 // in the label are preserved.
267 is >> std::noskipws >> ch;
268 while ((ch != '"') && !is.eof())
269 {
270 label.push_back(ch);
271 is >> ch;
272 }
273 if (ch != '"')
274 {
275 throw mcrl2::runtime_error("Expect that the second item is a quoted label (using \") at line " + std::to_string(line_no) + ".");
276 }
277 is >> std::skipws >> ch;
278 }
279 else
280 {
281 // In case the label is not within quotes,
282 // whitespaces are removed from the label.
283 label = ch;
284 is >> ch;
285 while ((ch != ',') && !is.eof())
286 {
287 label.push_back(ch);
288 is >> ch;
289 }
290 }
291
292 if (ch != ',')
293 {
294 throw mcrl2::runtime_error("Expect a comma after the quoted label at line " + std::to_string(line_no) + ".");
295 }
296
297 return true;
298}
299
301 std::istream& is,
302 std::size_t& from,
303 std::string& label,
305 const std::size_t line_no)
306{
308 {
309 return false;
310 }
311
312 read_probabilistic_state(is,target_probabilistic_state,line_no);
313
314 char ch;
315 is >> ch;
316 if (ch != ')')
317 {
318 throw mcrl2::runtime_error("Expect a closing bracket at the end of the transition at line " + std::to_string(line_no) + ".");
319 }
320
321 read_newline(is,line_no);
322 return true;
323}
324
326 std::istream& is,
327 std::size_t& from,
328 std::string& label,
329 std::size_t& to,
330 const std::size_t line_no)
331{
333 {
334 return false;
335 }
336
337 is >> std::skipws >> to;
338
339 char ch;
340 is >> ch;
341 if (ch != ')')
342 {
343 throw mcrl2::runtime_error("Expect a closing bracket at the end of the transition at line " + std::to_string(line_no) + ".");
344 }
345
346 read_newline(is,line_no);
347 return true;
348}
349
353 mcrl2::utilities::unordered_map < std::size_t, std::size_t>& indices_of_single_probabilistic_states,
354 mcrl2::utilities::unordered_map < mcrl2::lts::probabilistic_lts_aut_t::probabilistic_state_t, std::size_t>&
355 indices_of_multiple_probabilistic_states)
356{
357 std::size_t fresh_index = indices_of_single_probabilistic_states.size()+indices_of_multiple_probabilistic_states.size();
358 std::size_t index;
359 // Check whether probabilistic states exists.
360 if (probabilistic_state.size()<=1)
361 {
362 index = indices_of_single_probabilistic_states.insert(
363 std::pair< std::size_t, std::size_t>
364 (probabilistic_state.get(),fresh_index)).first->second;
365 }
366 else
367 {
368 assert(probabilistic_state.size()>1);
369 index = indices_of_multiple_probabilistic_states.insert(
370 std::pair< mcrl2::lts::probabilistic_lts_aut_t::probabilistic_state_t, std::size_t>
371 (probabilistic_state,fresh_index)).first->second;
372 }
373
374 if (index==fresh_index)
375 {
376 std::size_t probabilistic_state_index=l.add_and_reset_probabilistic_state(probabilistic_state);
377 assert(probabilistic_state_index==index);
378 (void)probabilistic_state_index; // Avoid unused variable warning.
379 }
380 return index;
381}
382
383
384static void read_from_aut(probabilistic_lts_aut_t& l, std::istream& is)
385{
386 std::size_t line_no = 1;
387 std::size_t ntrans=0, nstate=0;
388
390 read_aut_header(is,initial_probabilistic_state,ntrans,nstate);
391
392 // The two unordered maps below are used to determine a unique index for each probabilistic state.
393 // Because most states consist of one probabilistic state, the unordered maps are duplicated into
394 // indices_of_single_probabilistic_states and indices_of_multiple_probabilistic_states.
395 // The map indices_of_single_probabilistic_states requires far less memory.
396 mcrl2::utilities::unordered_map < std::size_t, std::size_t> indices_of_single_probabilistic_states;
397 mcrl2::utilities::unordered_map < mcrl2::lts::probabilistic_lts_aut_t::probabilistic_state_t, std::size_t> indices_of_multiple_probabilistic_states;
398
399 check_states(initial_probabilistic_state, nstate, line_no);
400
401 if (nstate==0)
402 {
403 throw mcrl2::runtime_error("cannot parse AUT input that has no states; at least an initial state is required.");
404 }
405
406 l.set_num_states(nstate,false);
407 l.clear_transitions(ntrans); // Reserve enough space for the transitions.
408
409 mcrl2::utilities::unordered_map < action_label_string, std::size_t > action_labels;
410 action_labels[action_label_string::tau_action()]=0; // A tau action is always stored at position 0.
411 l.set_initial_probabilistic_state(initial_probabilistic_state);
412
414 std::size_t from;
415 std::string s;
416
417 while (!is.eof())
418 {
419 probabilistic_target_state.clear();
420
421 line_no++;
422
423 if (!read_aut_transition(is,from,s,probabilistic_target_state,line_no))
424 {
425 break; // encountered EOF or something that is not a transition
426 }
427
428 check_state(from, nstate, line_no);
429 check_states(probabilistic_target_state, nstate, line_no);
430 std::size_t index = add_probablistic_state(probabilistic_target_state, l, indices_of_single_probabilistic_states, indices_of_multiple_probabilistic_states);
431
432 l.add_transition(transition(from,find_label_index(s,action_labels,l),index));
433 }
434
435 if (ntrans != l.num_transitions())
436 {
437 throw mcrl2::runtime_error("number of transitions read (" + std::to_string(l.num_transitions()) +
438 ") does not correspond to the number of transition given in the header (" + std::to_string(ntrans) + ").");
439 }
440}
441
442static void read_from_aut(lts_aut_t& l, std::istream& is)
443{
444 std::size_t line_no = 1;
445 std::size_t ntrans=0, nstate=0;
446
448 read_aut_header(is,initial_probabilistic_state,ntrans,nstate);
449
450 if (initial_probabilistic_state.size()>1)
451 {
452 throw mcrl2::runtime_error("Encountered an initial probability distribution while reading an non probabilistic .aut file.");
453 }
454
455 check_states(initial_probabilistic_state, nstate, line_no);
456
457 if (nstate==0)
458 {
459 throw mcrl2::runtime_error("cannot parse AUT input that has no states; at least an initial state is required.");
460 }
461
462 l.set_num_states(nstate,false);
463 l.clear_transitions(ntrans); // Reserve enough space for the transitions.
464
465 mcrl2::utilities::unordered_map < action_label_string, std::size_t > action_labels;
466 action_labels[action_label_string::tau_action()]=0; // A tau action is always stored at position 0.
467 l.set_initial_state(initial_probabilistic_state.get());
468
469 std::size_t from, to;
470 std::string s;
471 while (!is.eof())
472 {
473 line_no++;
474
475 if (!read_aut_transition(is,from,s,to,line_no))
476 {
477 break; // eof encountered
478 }
479
480 check_state(from, nstate, line_no);
481 check_state(to, nstate, line_no);
482 l.add_transition(transition(from,find_label_index(s,action_labels,l),to));
483 }
484
485 if (ntrans != l.num_transitions())
486 {
487 throw mcrl2::runtime_error("number of transitions read (" + std::to_string(l.num_transitions()) +
488 ") does not correspond to the number of transition given in the header (" + std::to_string(ntrans) + ").");
489 }
490}
491
492
494{
496 bool first_element=true;
497 if (prob_state.size()<=1) // This is a simple probabilistic state.
498 {
499 os << prob_state.get();
500 }
501 else // The state consists of a vector of states and probability pairs.
502 {
504 {
505 if (first_element)
506 {
507 os << p.state();
508 previous_probability=p.probability();
509 first_element=false;
510 }
511 else
512 {
513 os << " " << pp(previous_probability) << " " << p.state();
514 previous_probability=p.probability();
515 }
516 }
517 }
518}
519
520static void write_to_aut(const probabilistic_lts_aut_t& l, std::ostream& os)
521{
522 // Do not use "endl" below to avoid flushing. Use "\n" instead.
523 os << "des (";
525
526 os << "," << l.num_transitions() << "," << l.num_states() << ")" << "\n";
527
528 for (const transition& t: l.get_transitions())
529 {
530 os << "(" << t.from() << ",\"" << pp(l.action_label(l.apply_hidden_label_map(t.label()))) << "\",";
532 os << ")" << "\n";
533 }
534}
535
536static void write_to_aut(const lts_aut_t& l, std::ostream& os)
537{
538 // Do not use "endl" below to avoid flushing. Use "\n" instead.
539 os << "des (" << l.initial_state() << "," << l.num_transitions() << "," << l.num_states() << ")" << "\n";
540
541 for (const transition& t: l.get_transitions())
542 {
543 os << "(" << t.from() << ",\""
544 << pp(l.action_label(l.apply_hidden_label_map(t.label()))) << "\","
545 << t.to() << ")" << "\n";
546 }
547}
548
549namespace mcrl2
550{
551namespace lts
552{
553
554void probabilistic_lts_aut_t::load(const std::string& filename)
555{
556 if (filename=="" || filename=="-")
557 {
558 read_from_aut(*this, std::cin);
559 }
560 else
561 {
562 std::ifstream is(filename.c_str());
563
564 if (!is.is_open())
565 {
566 throw mcrl2::runtime_error("cannot open .aut file '" + filename + ".");
567 }
568
569 read_from_aut(*this,is);
570 is.close();
571 }
572}
573
574void probabilistic_lts_aut_t::load(std::istream& is)
575{
576 read_from_aut(*this,is);
577}
578
579void probabilistic_lts_aut_t::save(std::string const& filename) const
580{
581 if (filename=="" || filename=="-")
582 {
583 write_to_aut(*this, std::cout);
584 }
585 else
586 {
587 std::ofstream os(filename.c_str());
588
589 if (!os.is_open())
590 {
591 throw mcrl2::runtime_error("cannot create .aut file '" + filename + ".");
592 return;
593 }
594 write_to_aut(*this,os);
595 os.close();
596 }
597}
598
599void lts_aut_t::load(const std::string& filename)
600{
601 if (filename.empty() || filename=="-")
602 {
603 read_from_aut(*this, std::cin);
604 }
605 else
606 {
607 std::ifstream is(filename.c_str());
608
609 if (!is.is_open())
610 {
611 throw mcrl2::runtime_error("cannot open .aut file '" + filename + ".");
612 }
613
614 read_from_aut(*this,is);
615 is.close();
616 }
617}
618
619void lts_aut_t::load(std::istream& is)
620{
621 read_from_aut(*this,is);
622}
623
624void lts_aut_t::save(std::string const& filename) const
625{
626 if (filename.empty() || filename=="-")
627 {
628 write_to_aut(*this, std::cout);
629 }
630 else
631 {
632 std::ofstream os(filename.c_str());
633
634 if (!os.is_open())
635 {
636 throw mcrl2::runtime_error("cannot create .aut file '" + filename + ".");
637 return;
638 }
639 write_to_aut(*this,os);
640 os.close();
641 }
642}
643
644
645}
646}
Read-only balanced binary tree of terms.
This class contains strings to be used as values for action labels in lts's.
static const action_label_string & tau_action()
A simple labelled transition format with only strings as action labels.
Definition lts_aut.h:70
void load(const std::string &filename)
Load the labelled transition system from a file.
void save(const std::string &filename) const
Save the labelled transition system to file.
A class that contains a labelled transition system.
Definition lts.h:83
void add_transition(const transition &t)
Add a transition to the lts.
Definition lts.h:563
states_size_type num_states() const
Gets the number of states of this LTS.
Definition lts.h:245
void clear_transitions(const std::size_t n=0)
Clear the transitions of an lts.
Definition lts.h:493
void set_num_states(const states_size_type n, const bool has_state_labels=true)
Sets the number of states of this LTS.
Definition lts.h:280
ACTION_LABEL_T action_label(const labels_size_type action) const
Gets the label of an action.
Definition lts.h:479
void set_initial_state(const states_size_type state)
Sets the initial state number of this LTS.
Definition lts.h:343
labels_size_type apply_hidden_label_map(const labels_size_type action) const
If the action label is registered hidden, it returns tau, otherwise the original label.
Definition lts.h:447
const std::vector< transition > & get_transitions() const
Gets a const reference to the vector of transitions of the current lts.
Definition lts.h:545
states_size_type initial_state() const
Gets the initial state number of this LTS.
Definition lts.h:335
transitions_size_type num_transitions() const
Gets the number of transitions of this LTS.
Definition lts.h:302
A simple labelled transition format with only strings as action labels.
Definition lts_aut.h:103
void load(const std::string &filename)
Load the labelled transition system from a file.
void save(const std::string &filename) const
Save the labelled transition system to file.
void set_initial_probabilistic_state(const PROBABILISTIC_STATE_T &state)
Sets the probabilistic initial state number of this LTS.
const PROBABILISTIC_STATE_T & initial_probabilistic_state() const
Gets the initial state number of this LTS.
states_size_type add_and_reset_probabilistic_state(PROBABILISTIC_STATE_T &s)
Adds a probabilistic state to this LTS and resets the state to empty.
const PROBABILISTIC_STATE_T & probabilistic_state(const states_size_type index) const
Gets the probabilistic label of an index.
void set(const STATE &s)
Set this probabilistic state to a single state with probability one.
std::size_t size() const
Gets the number of probabilistic states in the vector representation of this state....
STATE get() const
Get a probabilistic state if is is simple, i.e., consists of a single state.
void clear()
Makes the probabilistic state empty.
void add(const STATE &s, const PROBABILITY &p)
Add a state with a probability to the probabilistic state.
A class containing triples, source label and target representing transitions.
Definition transition.h:48
Standard exception class for reporting runtime errors.
Definition exception.h:27
This class contains labels for probabilistic transistions, consisting of a numerator and a denominato...
static probabilistic_arbitrary_precision_fraction & one()
Constant one.
iterator find(const Args &... args)
std::pair< iterator, bool > insert(const value_type &pair)
Inserts elements.
const T & at(const key_type &key) const
Provides access to the value associated with the given key.
typename Set::const_iterator const_iterator
static void read_probabilistic_state(std::istream &is, mcrl2::lts::probabilistic_lts_aut_t::probabilistic_state_t &result, const std::size_t line_no)
static void write_probabilistic_state(const mcrl2::lts::probabilistic_lts_aut_t::probabilistic_state_t &prob_state, std::ostream &os)
static void read_from_aut(probabilistic_lts_aut_t &l, std::istream &is)
static size_t add_probablistic_state(mcrl2::lts::probabilistic_lts_aut_t::probabilistic_state_t &probabilistic_state, probabilistic_lts_aut_t &l, mcrl2::utilities::unordered_map< std::size_t, std::size_t > &indices_of_single_probabilistic_states, mcrl2::utilities::unordered_map< mcrl2::lts::probabilistic_lts_aut_t::probabilistic_state_t, std::size_t > &indices_of_multiple_probabilistic_states)
static void read_newline(std::istream &is, const std::size_t line_no)
static void read_aut_header(std::istream &is, mcrl2::lts::probabilistic_lts_aut_t::probabilistic_state_t &initial_state, std::size_t &num_transitions, std::size_t &num_states)
static void write_to_aut(const probabilistic_lts_aut_t &l, std::ostream &os)
static bool read_initial_part_of_an_aut_transition(std::istream &is, std::size_t &from, std::string &label, const std::size_t line_no)
static void read_natural_number_to_string(std::istream &is, std::string &s, const std::size_t line_no)
static void check_states(mcrl2::lts::probabilistic_lts_aut_t::probabilistic_state_t &probability_state, std::size_t number_of_states, std::size_t line_no)
static void check_state(std::size_t state, std::size_t number_of_states, std::size_t line_no)
static bool read_aut_transition(std::istream &is, std::size_t &from, std::string &label, mcrl2::lts::probabilistic_lts_aut_t::probabilistic_state_t &target_probabilistic_state, const std::size_t line_no)
static std::size_t find_label_index(const std::string &s, mcrl2::utilities::unordered_map< action_label_string, std::size_t > &labs, AUT_LTS_TYPE &l)
This file contains a class that contains labelled transition systems in aut format.
std::string pp(const abstraction &x)
Definition data.cpp:39
atermpp::term_balanced_tree< data::data_expression > state
Definition state.h:24
The main LTS namespace.
std::size_t to(const outgoing_pair_t &p)
Target state of a label state pair.
std::size_t label(const outgoing_pair_t &p)
Label of a pair of a label and target state.
std::size_t from(const outgoing_transitions_per_state_action_t::const_iterator &i)
From state of an iterator exploring transitions per outgoing state and action.
A class that takes a linear process specification and checks all tau-summands of that LPS for conflue...
Definition indexed_set.h:72