mCRL2
Loading...
Searching...
No Matches
symbolic_lts_bisim.h
Go to the documentation of this file.
1// Author(s): Maurice Laveaux
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
10#ifndef MCRL2_LPS_SYMBOLIC_LTS_BISIM_H
11#define MCRL2_LPS_SYMBOLIC_LTS_BISIM_H
12
13#ifdef MCRL2_ENABLE_SYLVAN
14
18
19#include <sylvan_ldd.hpp>
20
21namespace mcrl2::lps
22{
23
24namespace
25{
26
27struct result
28{
29 sylvan::ldds::ldd projected;
30 std::size_t action_index;
31};
32
33} // anonymous namespace
34
36template <typename Context>
37void project_transitions(WorkerP*, Task*, std::uint32_t* x, std::size_t n, void* context)
38{
39 using namespace sylvan::ldds;
40
41 auto pointer = reinterpret_cast<Context*>(context);
42 auto& p = *pointer;
43
44 if (x[n-1] == p.action_index)
45 {
46 p.projected = union_(p.projected, cube(x, n));
47 }
48}
49
51std::size_t height(const sylvan::ldds::ldd& x)
52{
53 using namespace sylvan::ldds;
54 return sat_one_vector(x).size();
55}
56
58sylvan::ldds::ldd project_transitions(const sylvan::ldds::ldd& x, std::size_t height, std::size_t action_index)
59{
60 using namespace sylvan::ldds;
61
62 if (x == empty_set() || x == empty_list())
63 {
64 return x;
65 }
66
67 if (height == 1)
68 {
69 // We are at the action label depth (keep only action_index).
70 if (x.value() < action_index)
71 {
72 return project_transitions(x.right(), height, action_index);
73 }
74 else if (x.value() == action_index)
75 {
76 return node(x.value());
77 }
78 else
79 {
80 return false_();
81 }
82 }
83 else
84 {
85 return node(x.value(), project_transitions(x.down(), height - 1, action_index), project_transitions(x.right(), height, action_index));
86 }
87}
88
89void bisim(const symbolic_lts& lts)
90{
91 using namespace sylvan::ldds;
92
93 // Split all transition groups such that there is only one action label for each.
94 mCRL2log(log::verbose) << "Preprocessing the transition groups..." << std::endl;
95 std::vector<lps_summand_group> new_groups;
96
97 for (const auto& group : lts.summand_groups)
98 {
99 for (const auto& action : lts.action_index)
100 {
101 // Explore all transitions in the LDD.
102 result res;
103 //res.action_index = lts.action_index.index(action);
104 //sat_all_nopar(group.L, project_transitions<result>, &res);
105 res.projected = project_transitions(group.L, height(group.L), lts.action_index.index(action));
106
107 if (res.projected != sylvan::ldds::empty_set())
108 {
109 new_groups.emplace_back(group);
110 new_groups.back().L = res.projected;
111 }
112 }
113 }
114
115 mcrl2::utilities::unordered_set<ldd> partition; // The set of sets of states, where each set of states is an LDD.
117 partition.emplace(lts.states);
118
119 bool refined_block = false;
120 bool refined_any_block = false;
121 std::size_t iterations = 0;
122
123 mCRL2log(log::verbose) << "Starting signature refinement..." << std::endl;
124 do
125 {
126 refined_any_block = false;
127
128 for (const ldd& C : partition)
129 {
130 refined_block = false;
131
132 for (const ldd& C_prime : partition)
133 {
134 // Refine each block one by one.
135 for (const lps_summand_group& group : new_groups)
136 {
137 ldd A = relprev(C_prime, group.L, group.Ir, C);
138 if (A != sylvan::ldds::empty_set() && A != C)
139 {
140 // This block must be refined.
141 new_partition.emplace(A),
142 new_partition.emplace(minus(C, A));
143 refined_block = true;
144 break;
145 }
146 }
147
148 if (refined_block)
149 {
150 refined_any_block = true;
151 break;
152 }
153 }
154
155 if (!refined_block)
156 {
157 new_partition.emplace(C); // Keep the old block for the next iteration.
158 }
159 }
160
161 swap(partition, new_partition);
162 new_partition.clear();
163
164 ++iterations;
165 mCRL2log(log::verbose) << "found " << std::setw(12) << partition.size() << " equivalence classes after " << std::setw(4) << iterations << " iterations." << std::endl;
166 }
167 while (refined_any_block);
168
169 // The partition is now a bisimulation.
170 mCRL2log(log::verbose) << "There are " << partition.size() << " equivalence classes." << std::endl;
171 for (const ldd& C : partition)
172 {
173 mCRL2log(log::debug) << symbolic::print_size(C, true, true) << std::endl;
174 mCRL2log(log::debug) << symbolic::print_states(lts.data_index, C) << std::endl;
175 }
176}
177
178} // namespace mcrl2::lps
179
180#endif // MCRL2_ENABLE_SYLVAN
181
182#endif // MCRL2_LPS_SYMBOLIC_LTS_BISIM_H
A unordered_set with a subset of the interface of std::unordered_set that only stores a single pointe...
std::pair< iterator, bool > emplace(Args &&... args)
Inserts an element Key(args...) into the set if it did not already exist.
size_type size() const noexcept
void clear()
Removes all elements from the set.
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:391
function_symbol union_(const sort_expression &s, const sort_expression &s0, const sort_expression &s1)
Definition bag1.h:426
const function_symbol & false_()
Constructor for function symbol false.
Definition bool.h:109
function_symbol minus(const sort_expression &s0, const sort_expression &s1)
Definition int1.h:1039
@ verbose
Definition logger.h:37
The main namespace for the LPS library.
void swap(action_summand &t1, action_summand &t2)
\brief swap overload
T * pointer(const T *p)