mCRL2
Loading...
Searching...
No Matches
liblts_lts.cpp
Go to the documentation of this file.
1// Author(s): Muck van Weerdenburg; completely rewritten by 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//
9/// \file liblts_lts.cpp
10
11#include <algorithm>
12#include <fstream>
13#include <optional>
14
15#include "mcrl2/atermpp/standard_containers/indexed_set.h"
16
17#include "mcrl2/lts/lts_lts.h"
18#include "mcrl2/lts/lts_io.h"
19
20
21namespace mcrl2::lts
22{
23
24/// \brief Converts a probabilistic state into an aterm that encodes it.
25atermpp::aterm_ostream& operator<<(atermpp::aterm_ostream& stream, const probabilistic_lts_lts_t::probabilistic_state_t& state)
26{
27 if (state.size()==0)
28 {
29 // The probabilistic state is represented as a singular state and is stored without probability;
30 stream << atermpp::aterm_int(1);
31 stream << atermpp::aterm_int(state.get());
32 }
33 else if (state.size()<=1)
34 {
35 // The probabilistic state is the single element in a vector and is stored without probability;
36 stream << atermpp::aterm_int(1);
37 stream << atermpp::aterm_int(state.get());
38 }
39 else
40 {
41 // The probabilistic state is stored as a sequence of state probability pairs.
42 stream << atermpp::aterm_int(state.size());
43
44 for(const auto& p : state)
45 {
46 // Push a (index, probability) pair into the list.
47 stream << atermpp::aterm_int(p.state());
48 stream << p.probability();
49 }
50 }
51
52 return stream;
53}
54
55atermpp::aterm_istream& operator>>(atermpp::aterm_istream& stream, probabilistic_lts_lts_t::probabilistic_state_t& state)
56{
57 atermpp::aterm_int index;
58 stream >> index; // Read the number of states.
59
60 const std::size_t value=index.value();
61 assert(value>0);
62 if (value==1)
63 {
64 stream >> index;
65 state.set(index.value());
66 }
67 else
68 {
69 state.clear();
71
72 for (std::size_t i = 0; i < value; ++i)
73 {
74 stream >> index;
75 stream >> probability;
76
77 state.add(index.value(), probability);
78 }
79
80 state.shrink_to_fit();
81 }
82 return stream;
83}
84
85namespace detail
86{
87
88using namespace atermpp;
89
90// Special terms to indicate the type of the following structure.
91
93{
94 static const atermpp::aterm plain_mark(atermpp::function_symbol("transition", 0));
95 return plain_mark;
96}
97
99{
100 static atermpp::aterm probabilistic_mark(atermpp::function_symbol("probabilistic_transition", 0));
101 return probabilistic_mark;
102}
103
105{
106 static const atermpp::aterm initial_state_mark(atermpp::function_symbol("initial_state", 0));
107 return initial_state_mark;
108}
109
111{
112 static const atermpp::aterm lts_mark(atermpp::function_symbol("labelled_transition_system", 0));
113 return lts_mark;
114}
115
116// Utility functions
117
118static void set_initial_state(lts_lts_t& lts, const probabilistic_lts_lts_t::probabilistic_state_t& initial_state)
119{
120 if (initial_state.size() > 1)
121 {
122 throw mcrl2::runtime_error("The initial state of the non probabilistic input lts is probabilistic.");
123 }
124
125 lts.set_initial_state(initial_state.get());
126}
127
128static void set_initial_state(probabilistic_lts_lts_t& lts, const probabilistic_lts_lts_t::probabilistic_state_t& initial_state)
129{
130 lts.set_initial_probabilistic_state(initial_state);
131}
132
133template <class LTS>
134static void read_lts(atermpp::aterm_istream& stream, LTS& lts)
135{
136 static_assert(std::is_same_v<LTS, probabilistic_lts_lts_t> || std::is_same_v<LTS, lts_lts_t>,
137 "Function read_lts can only be applied to a (probabilistic) lts. ");
138
139 atermpp::aterm_stream_state state(stream);
141
142 atermpp::aterm marker;
143 stream >> marker;
144
146 {
147 throw mcrl2::runtime_error("Stream does not contain a labelled transition system (LTS).");
148 }
149
150 // Read the header of the lts.
152 data::variable_list parameters;
153 process::action_label_list action_labels;
154
155 stream >> spec;
156 stream >> parameters;
157 stream >> action_labels;
158
159 lts.set_data(spec);
160 lts.set_process_parameters(parameters);
161 lts.set_action_label_declarations(action_labels);
162
163 // An indexed set to keep indices for multi actions.
164 mcrl2::utilities::indexed_set<action_label_lts> multi_actions;
165 multi_actions.insert(action_label_lts::tau_action()); // This action list represents 'tau'.
166
167 // The initial state is stored and set as last.
168 std::optional<probabilistic_lts_lts_t::probabilistic_state_t> initial_state;
169
170 // Ensure unique indices for the probabilistic states.
171 mcrl2::utilities::indexed_set<
172 probabilistic_lts_lts_t::probabilistic_state_t> probabilistic_states;
173
174 // Keep track of the number of states (derived from the transitions).
175 std::size_t number_of_states = 1;
176
177 aterm term;
178 aterm_int from;
179 action_label_lts action;
180 aterm_int to;
181
182 while (true)
183 {
184 stream.get(term);
185 if (!term.defined())
186 {
187 // The default constructed term indicates the end of the stream.
188 break;
189 }
190
191 if (term == transition_mark())
192 {
193 stream >> from;
194 stream >> action;
195 stream >> to;
196
197 const auto [index, inserted] = multi_actions.insert(action);
198
199 std::size_t target_index = to.value();
200 if constexpr (std::is_same_v<LTS, probabilistic_lts_lts_t>)
201 {
202 probabilistic_lts_lts_t::probabilistic_state_t lts_state(to.value());
203
204 // For probabilistic lts it is necessary to add the state first (and use the returned index).
205 bool state_inserted;
206 std::tie(target_index, state_inserted) = probabilistic_states.insert(lts_state);
207
208 if (state_inserted)
209 {
210 [[maybe_unused]]
211 std::size_t actual_index = lts.add_probabilistic_state(lts_state);
212 assert(actual_index == target_index);
213 }
214 }
215
216 // Add the transition and update the number of states.
217 lts.add_transition(transition(from.value(), index, target_index));
218 number_of_states = std::max({number_of_states, from.value() + 1, to.value() + 1});
219
220 if (inserted)
221 {
222 [[maybe_unused]]
223 std::size_t actual_index = lts.add_action(action);
224 assert(actual_index == index);
225 }
226
227 }
228 else if(term == probabilistic_transition_mark())
229 {
230 if constexpr (std::is_same_v<LTS, probabilistic_lts_lts_t>)
231 {
232 probabilistic_lts_lts_t::probabilistic_state_t to;
233
234 stream >> from;
235 stream >> action;
236 stream >> to;
237
238 const auto [index, inserted] = multi_actions.insert(action);
239
240 // Compute the index of the probabilistic state.
241 const auto [to_index, state_inserted] = probabilistic_states.insert(to);
242
243 if (state_inserted)
244 {
245 [[maybe_unused]]
246 std::size_t actual_index = lts.add_probabilistic_state(to);
247 assert(actual_index == to_index);
248 }
249
250 lts.add_transition(transition(from.value(), index, to_index));
251
252 // Update the number of states
253 number_of_states = std::max({number_of_states, from.value() + 1, to.maximal_state() + 1});
254
255 if (inserted)
256 {
257 [[maybe_unused]]
258 std::size_t actual_index = lts.add_action(action);
259 assert(actual_index == index);
260 }
261 }
262 else
263 {
264 throw mcrl2::runtime_error("Attempting to read a probabilistic LTS as a regular LTS.");
265 }
266 }
267 else if (term.type_is_list())
268 {
269 // Lists always represent state labels, only need to add the indices.
270 lts.add_state(reinterpret_cast<const state_label_lts&>(term));
271 }
272 else if (term == initial_state_mark())
273 {
274 // Read the initial state.
275 probabilistic_lts_lts_t::probabilistic_state_t state;
276 stream >> state;
277 initial_state = state;
278 }
279 else
280 {
281 throw mcrl2::runtime_error("Unknown mark in labelled transition system (LTS) stream.");
282 }
283 }
284
285 // The initial state can only be set after the states are known.
286 if (initial_state)
287 {
288 // If the lts has no state labels, we need to add empty states labels.
289 lts.set_num_states(number_of_states, lts.has_state_info());
290
291 set_initial_state(lts, initial_state.value());
292 }
293 else
294 {
295 throw mcrl2::runtime_error("Missing initial state in labelled transition system (LTS) stream.");
296 }
297}
298
299template <class LTS_TRANSITION_SYSTEM>
300static void read_from_lts(LTS_TRANSITION_SYSTEM& lts, const std::string& filename)
301{
302 static_assert(std::is_same_v<LTS_TRANSITION_SYSTEM, probabilistic_lts_lts_t>
303 || std::is_same_v<LTS_TRANSITION_SYSTEM, lts_lts_t>,
304 "Function read_from_lts can only be applied to a (probabilistic) lts. ");
305
306 std::ifstream fstream;
307 if (!filename.empty())
308 {
309 fstream.open(filename, std::ifstream::in | std::ifstream::binary);
310 if (fstream.fail())
311 {
312 if (filename.empty())
313 {
314 throw mcrl2::runtime_error("Fail to open standard input to read an lts.");
315 }
316 else
317 {
318 throw mcrl2::runtime_error("Fail to open file " + filename + " to read an lts.");
319 }
320 }
321 }
322
323 try
324 {
325 atermpp::binary_aterm_istream stream(filename.empty() ? std::cin : fstream);
326 stream >> lts;
327 }
328 catch (const std::exception& ex)
329 {
330 mCRL2log(log::log_level_t::error) << ex.what() << "\n";
331 if (filename.empty())
332 {
333 throw mcrl2::runtime_error("Fail to correctly read an lts from standard input.");
334 }
335 else
336 {
337 throw mcrl2::runtime_error("Fail to correctly read an lts from the file " + filename + ".");
338 }
339 }
340}
341
343{
345 stream << lts.initial_probabilistic_state();
346}
347
349{
351 stream << probabilistic_lts_lts_t::probabilistic_state_t(lts.initial_state());
352}
353
354template <class LTS>
355static void write_lts(atermpp::aterm_ostream& stream, const LTS& lts)
356{
357 static_assert(std::is_same_v<LTS, probabilistic_lts_lts_t> || std::is_same_v<LTS, lts_lts_t>,
358 "Function write_lts can only be applied to a (probabilistic) lts. ");
359
360 // Write the process related information.
361 write_lts_header(stream,
362 lts.data(),
363 lts.process_parameters(),
364 lts.action_label_declarations());
365
366 for (const transition& trans : lts.get_transitions())
367 {
368 lts_lts_t::action_label_t label = lts.action_label(lts.apply_hidden_label_map(trans.label()));
369
370 if constexpr (std::is_same_v<LTS, probabilistic_lts_lts_t>)
371 {
372 write_transition(stream, trans.from(), label, lts.probabilistic_state(trans.to()));
373 }
374 else
375 {
376 write_transition(stream, trans.from(), label, trans.to());
377 }
378 }
379
380 if (lts.has_state_info())
381 {
382 for (std::size_t i = 0; i < lts.num_state_labels(); ++i)
383 {
384 // Write state labels as such, we assume that all list terms without headers are state labels.
385 stream << lts.state_label(i);
386 }
387 }
388
389 // Write the initial state.
390 write_initial_state(stream, lts);
391}
392
393template <class LTS_TRANSITION_SYSTEM>
394static void write_to_lts(const LTS_TRANSITION_SYSTEM& lts, const std::string& filename)
395{
396 static_assert(std::is_same_v<LTS_TRANSITION_SYSTEM, probabilistic_lts_lts_t>
397 || std::is_same_v<LTS_TRANSITION_SYSTEM, lts_lts_t>,
398 "Function write_to_lts can only be applied to a (probabilistic) lts. ");
399
400 bool to_stdout = filename.empty() || filename == "-";
401 std::ofstream fstream;
402 if (!to_stdout)
403 {
404 fstream.open(filename, std::ofstream::out | std::ofstream::binary);
405 if (fstream.fail())
406 {
407 throw mcrl2::runtime_error("Fail to open file " + filename + " for writing.");
408 }
409 }
410
411 try
412 {
413 atermpp::binary_aterm_ostream stream(to_stdout ? std::cout : fstream);
414 stream << lts;
415 }
416 catch (const std::exception& ex)
417 {
418 mCRL2log(log::log_level_t::error) << ex.what() << "\n";
419 throw mcrl2::runtime_error("Fail to write lts correctly to the file " + filename + ".");
420 }
421}
422
423} // namespace detail
424
425// Implementation of public functions.
426
428{
429 read_lts(stream, lts);
430 return stream;
431}
432
434{
435 read_lts(stream, lts);
436 return stream;
437}
438
439atermpp::aterm_ostream& operator<<(atermpp::aterm_ostream& stream, const lts_lts_t& lts)
440{
441 detail::write_lts(stream, lts);
442 return stream;
443}
444
446{
447 detail::write_lts(stream, lts);
448 return stream;
449}
450
452 const data::data_specification& data_spec,
453 const data::variable_list& parameters,
454 const process::action_label_list& action_labels)
455{
456 // We set the transformer for all other elements (transitions, state labels and the initial state).
458
459 // Write the header of the lts.
461 stream << data_spec;
462 stream << parameters;
463 stream << action_labels;
464}
465
466void write_transition(atermpp::aterm_ostream& stream, std::size_t from, const lps::multi_action& label, std::size_t to)
467{
469 stream << atermpp::aterm_int(from);
470 stream << label;
471 stream << atermpp::aterm_int(to);
472}
473
474void write_transition(atermpp::aterm_ostream& stream, std::size_t from, const lps::multi_action& label, const probabilistic_lts_lts_t::probabilistic_state_t& to)
475{
476 if (to.size() <= 1)
477 {
478 // Actually a non probabilistic transition.
479 write_transition(stream, from, label, to.get());
480 }
481 else
482 {
484 stream << atermpp::aterm_int(from);
485 stream << label;
486 stream << to;
487 }
488}
489
491{
492 // During reading we assume that state labels are the only aterm_list.
493 stream << label;
494}
495
496void write_initial_state(atermpp::aterm_ostream& stream, std::size_t index)
497{
499 stream << probabilistic_lts_lts_t::probabilistic_state_t(index);
500}
501
502void probabilistic_lts_lts_t::save(const std::string& filename) const
503{
504 mCRL2log(log::log_level_t::verbose) << "Starting to save a probabilistic lts to the file " << filename << ".\n";
505 detail::write_to_lts(*this, filename);
506}
507
508void lts_lts_t::save(std::string const& filename) const
509{
510 mCRL2log(log::log_level_t::verbose) << "Starting to save an lts to the file " << filename << ".\n";
511 detail::write_to_lts(*this, filename);
512}
513
514void probabilistic_lts_lts_t::load(const std::string& filename)
515{
516 mCRL2log(log::log_level_t::verbose) << "Starting to load a probabilistic lts from the file " << filename << ".\n";
517 detail::read_from_lts(*this, filename);
518}
519
520void lts_lts_t::load(const std::string& filename)
521{
522 mCRL2log(log::log_level_t::verbose) << "Starting to load an lts from the file " << filename << ".\n";
523 detail::read_from_lts(*this, filename);
524}
525
526} // namespace mcrl2::lts
An integer term stores a single std::size_t value. It carries no arguments.
Definition aterm_int.h:26
The interface for a class that reads aterm from a stream. The default constructed term aterm() indica...
Definition aterm_io.h:62
virtual void get(aterm &t)=0
Reads an aterm from this stream.
The interface for a class that writes aterm to a stream. Every written term is retrieved by the corre...
Definition aterm_io.h:51
A helper class to restore the state of the aterm_{i,o}stream objects upon destruction....
Definition aterm_io.h:104
aterm_stream_state(aterm_stream &stream)
Definition aterm_io.h:106
A unordered_map class in which aterms can be stored.
\brief A timed multi-action
This class contains labels for probabilistic transistions, consisting of a numerator and a denumerato...
A class containing the values for action labels for the .lts format.
Definition lts_lts.h:142
function object to compare two constln_t pointers based on their contents
This class contains labelled transition systems in .lts format.
Definition lts_lts.h:369
void save(const std::string &filename) const
Save the labelled transition system to file.
void load(const std::string &filename)
Load the labelled transition system from file.
This class contains probabilistic labelled transition systems in .lts format.
Definition lts_lts.h:397
void load(const std::string &filename)
Load the labelled transition system from file.
void save(const std::string &filename) const
Save the labelled transition system to file.
This class contains state labels for an labelled transition system in .lts format.
Definition lts_lts.h:38
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:435
aterm_istream & operator>>(aterm_istream &stream, aterm &term)
Read the given term from the stream, but for aterm_list we want to use a specific one that performs v...
Definition aterm_io.h:93
aterm_istream & operator>>(aterm_istream &stream, aterm_transformer transformer)
Sets the given transformer to be applied to following reads.
Definition aterm_io.h:73
atermpp::aterm remove_index_impl(const atermpp::aterm &x)
Definition io.h:23
atermpp::aterm add_index_impl(const atermpp::aterm &x)
Definition io.h:33
atermpp::aterm_istream & operator>>(atermpp::aterm_istream &stream, data_specification &spec)
Reads a data specification from a stream.
Definition data_io.cpp:61
The main namespace for the LPS library.
Definition constelm.h:18
static void set_initial_state(probabilistic_lts_lts_t &lts, const probabilistic_lts_lts_t::probabilistic_state_t &initial_state)
static const atermpp::aterm & initial_state_mark()
static void set_initial_state(lts_lts_t &lts, const probabilistic_lts_lts_t::probabilistic_state_t &initial_state)
static const atermpp::aterm & probabilistic_transition_mark()
static void write_to_lts(const LTS_TRANSITION_SYSTEM &lts, const std::string &filename)
void write_initial_state(atermpp::aterm_ostream &stream, const lts_lts_t &lts)
static void write_lts(atermpp::aterm_ostream &stream, const LTS &lts)
static void read_from_lts(LTS_TRANSITION_SYSTEM &lts, const std::string &filename)
static const atermpp::aterm & transition_mark()
void write_initial_state(atermpp::aterm_ostream &stream, const probabilistic_lts_lts_t &lts)
static void read_lts(atermpp::aterm_istream &stream, LTS &lts)
static const atermpp::aterm & labelled_transition_system_mark()
void write_transition(atermpp::aterm_ostream &stream, std::size_t from, const lps::multi_action &label, const probabilistic_lts_lts_t::probabilistic_state_t &to)
void write_lts_header(atermpp::aterm_ostream &stream, const data::data_specification &data, const data::variable_list &parameters, const process::action_label_list &action_labels)
Writes the start of an LTS stream.
void write_initial_state(atermpp::aterm_ostream &stream, std::size_t index)
Write the initial state to the LTS stream.
atermpp::aterm_istream & operator>>(atermpp::aterm_istream &stream, probabilistic_lts_lts_t &lts)
atermpp::aterm_istream & operator>>(atermpp::aterm_istream &stream, probabilistic_lts_lts_t::probabilistic_state_t &state)
void write_state_label(atermpp::aterm_ostream &stream, const state_label_lts &label)
Write a state label to the LTS stream.
void write_transition(atermpp::aterm_ostream &stream, std::size_t from, const lps::multi_action &label, std::size_t to)
Write a transition to the LTS stream.
atermpp::aterm_istream & operator>>(atermpp::aterm_istream &stream, lts_lts_t &lts)
Read a (probabilistic) LTS from the given stream.
The main namespace for the Process library.