22#ifndef _LIBLTS_COUPLED_SIM_H
23#define _LIBLTS_COUPLED_SIM_H
54 std::size_t
p; std::size_t
q;
64 std::string _label_of_action,
98 : n0.
p != n1.
p ? n0.
p < n1.
p
105 std::string fst = !n.
swapped ?
"p" :
"q";
106 std::string snd = !n.
swapped ?
"q" :
"p";
112 "(" + fst + std::to_string(n.
p) +
113 "," + snd + std::to_string(n.
q) +
")a";
117 + fst + std::to_string(n.
p) +
","
118 + snd + std::to_string(n.
q) +
")d";
122 "(" + std::to_string(n.
act) +
123 "," + fst + std::to_string(n.
p) +
124 "," + snd + std::to_string(n.
q) +
")d";
126 default:
return "(<strange node>)?";
134 bool weak_transition =
false)
136 return m0.
act == m1.
act && (!weak_transition && !(m0.
weak || m1.
weak));
147template <
class LTS_TYPE>
151 bool preserve_divergences =
true;
156 <<
"Input LTSs now reduced "
157 <<
"(preserve_divergences:" << (preserve_divergences ?
"true" :
"false") <<
"), "
158 <<
"continue with reduced version."
161 std::set<cs_game_node> attacker_nodes;
162 std::set<cs_game_node> defender_nodes;
164 std::map<cs_game_node,std::set<cs_game_node>> predecessors;
165 std::map<cs_game_node,int> successor_count;
166 std::map<cs_game_node,int> node_winner;
167 const int WIN_DEFENDER = 0, WIN_ATTACKER = 1;
170 std::set<cs_game_move> moves;
171 std::string move_label;
172 std::ostringstream stream;
177 std::stack<transition> todo_weak;
178 std::set<transition> l1_weak_transitions, l2_weak_transitions;
181 std::map<std::size_t, std::map<transition, bool>>
182 l2_tran_from_node, l2_tran_into_node,
183 l1_tran_from_node, l1_tran_into_node;
186 <<
"Find weak transitions."
190 for (
const transition& t1 : l1.get_transitions())
192 l1_tran_from_node[t1.from()][t1] =
true;
193 l1_tran_into_node[t1.to()][t1] =
true;
198 l1_weak_transitions.insert(t1);
201 l1_weak_transitions.insert(
transition(t1.from(), 0, t1.from()));
202 l1_weak_transitions.insert(
transition(t1.to(), 0, t1.to()));
207 while (!todo_weak.empty())
213 std::size_t f = weak.
from();
214 std::size_t l = weak.
label();
215 std::size_t t = weak.
to();
216 bool already_good = !l1.is_tau(l);
218 const std::map<transition,bool>& next = l1_tran_from_node[t];
219 std::size_t len = next.size();
223 l1_weak_transitions.insert(weak);
224 l1_tran_into_node[t][weak] |=
false;
225 l1_tran_from_node[f][weak] |=
false;
233 for (
const auto& ntrans : next)
235 std::size_t next_label = ntrans.first.label();
236 bool next_tau = l1.is_tau(next_label);
241 if (next_tau || !already_good)
246 !already_good ? next_label : l, ntrans.first.to());
249 todo_weak.push(new_extended_weak);
258 for (
const transition& t2 : l2.get_transitions())
260 l2_tran_from_node[t2.from()][t2] =
true;
261 l2_tran_into_node[t2.to()][t2] =
true;
265 l2_weak_transitions.insert(t2);
268 l2_weak_transitions.insert(
transition(t2.from(), 0, t2.from()));
269 l2_weak_transitions.insert(
transition(t2.to(), 0, t2.to()));
274 while (!todo_weak.empty())
280 std::size_t f = weak.
from();
281 std::size_t l = weak.
label();
282 std::size_t t = weak.
to();
283 bool already_good = !l2.is_tau(l);
285 const std::map<transition,bool>& next = l2_tran_from_node[t];
286 std::size_t len = next.size();
290 l2_weak_transitions.insert(weak);
291 l2_tran_into_node[t][weak] |=
false;
292 l2_tran_from_node[f][weak] |=
false;
300 for (
const auto &ntrans : next)
302 std::size_t next_label = ntrans.first.label();
303 bool next_tau = l2.is_tau(next_label);
308 if (next_tau || !already_good)
312 =
transition(f, !already_good ? next_label : l, ntrans.first.to());
315 todo_weak.push(new_extended_weak);
324 <<
"Creating now the cs-game arena."
327 for (std::size_t p0 = 0; p0 < l1.num_states(); p0++)
329 for (std::size_t q0 = 0; q0 < l2.num_states(); q0++)
338 attacker_nodes.insert(p0q0);
339 attacker_nodes.insert(q0p0);
340 defender_nodes.insert(cplp0q0);
341 defender_nodes.insert(cplq0p0);
343 moves.emplace(p0q0, cplp0q0, 0,
"cpl");
344 moves.emplace(q0p0, cplq0p0, 0,
"cpl");
347 moves.emplace(cplp0q0, q0p0, 0,
"bisim");
348 moves.emplace(cplq0p0, p0q0, 0,
"bisim");
350 std::map<cs_game_move, bool> todo_if;
358 for (
const auto& t1 : l1_tran_from_node[p0])
360 std::size_t a = t1.first.label();
361 std::size_t p1 = t1.first.to();
362 bool atau = l1.is_tau(a);
363 bool strong = t1.second;
365 stream << (l1.action_label(a));
366 move_label = stream.str();
377 defender_nodes.insert(ap1q0);
378 moves.emplace(p0q0, ap1q0, a, move_label);
383 attacker_nodes.insert(q0_stay);
384 moves.emplace(ap1q0, q0_stay, 0,
"");
392 for (
const transition &bq1 : l2.get_transitions())
394 std::size_t b = bq1.label(), q1 = bq1.to();
397 if (l2.action_label(b) == l1.action_label(a))
402 defender_nodes.insert(bqp0);
403 attacker_nodes.insert(qp1);
405 moves.emplace(bqp0, qp1, a, move_label);
413 attacker_nodes.insert(p0p1);
414 moves.emplace(cplq0p0, p0p1, 0,
"p \21d2 p'");
424 for (
const auto &t2 : l2_tran_from_node[q0])
426 std::size_t b = t2.first.label();
427 std::size_t q1 = t2.first.to();
428 bool btau = l2.is_tau(b);
429 bool strong = t2.second;
431 stream << (l2.action_label(b));
432 move_label = stream.str();
444 defender_nodes.insert(bq1p0);
445 moves.emplace(q0p0, bq1p0, b, move_label);
450 attacker_nodes.insert(p0_stay);
451 moves.emplace(bq1p0, p0_stay, 0,
"");
459 for (
const transition &ap1 : l1.get_transitions())
461 std::size_t a = ap1.label(), p1 = ap1.to();
464 if (l2.action_label(b) == l1.action_label(a))
469 defender_nodes.insert(apq0);
470 attacker_nodes.insert(pq1);
472 moves.emplace(apq0, pq1, b, move_label);
480 attacker_nodes.insert(q0q1);
481 moves.emplace(cplp0q0, q0q1, 0,
"q \21d2 q'");
488 << attacker_nodes.size() <<
" attacker nodes and "
489 << defender_nodes.size() <<
" defender nodes."
496 for (
const auto &m : moves)
502 node_winner[pred] = WIN_DEFENDER;
503 node_winner[succ] = WIN_DEFENDER;
507 predecessors[succ].insert(pred);
510 successor_count[pred] += 1;
513 std::stack<cs_game_node> todo;
514 for (
const cs_game_node& d : defender_nodes) todo.push(d);
518 <<
"Compute the winning area of the defender." << std::endl;
521 while (!todo.empty())
527 if (successor_count[n] <= 0)
529 if (node_winner[n] == WIN_DEFENDER)
531 node_winner[n] = WIN_ATTACKER;
538 successor_count[pred] -= 1;
539 if (successor_count[pred] < 1 || attacker_nodes.count(pred))
542 successor_count[pred] = 0;
550 <<
"Get coupled simulation from defender's winning area."
553 char seperator[3] = {
'\0',
' ',
'\0'};
557 std::set<cs_game_node> cs_relation;
558 for (
const auto &n : attacker_nodes)
561 if (node_winner.find(n) == node_winner.end())
564 <<
"I am requested, but never listed."
565 <<
" Set to default. (" <<
to_string(n) << std::endl;
569 if (node_winner[n] == WIN_DEFENDER)
571 cs_relation.insert(n);
581 = { {
NODE_ATK, 0, l1.initial_state(), l2.initial_state(),
false}
582 , {
NODE_ATK, 0, l2.initial_state(), l1.initial_state(),
true}};
585 = node_winner[roots[0]] == WIN_DEFENDER
586 && node_winner[roots[1]] == WIN_DEFENDER;
bool operator==(const ParityGameVertex &a, const ParityGameVertex &b)
bool operator!=(const ParityGameVertex &a, const ParityGameVertex &b)
A class containing triples, source label and target representing transitions.
size_type from() const
The source of the transition.
size_type label() const
The label of the transition.
size_type to() const
The target of the transition.
This file defines an algorithm for weak bisimulation, by calculating the transitive tau closure and a...
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
The file containing the core class for transition systems.
bool operator<(const action_summand &x, const action_summand &y)
Comparison operator for action summands.
const unsigned char NODE_ATK
bool coupled_simulation_compare(LTS_TYPE &l1, LTS_TYPE &l2)
void weak_bisimulation_reduce(LTS_TYPE &l, const bool preserve_divergences=false)
Reduce LTS l with respect to (divergence-preserving) weak bisimulation.
const unsigned char NODE_DEF
bool equals(const cs_game_move &m0, const cs_game_move &m1, bool weak_transition=false)
const unsigned char NODE_CPL
std::string to_string(const cs_game_node &n)
A class that takes a linear process specification and checks all tau-summands of that LPS for conflue...
std::string label_of_action
cs_game_move(cs_game_node _from, cs_game_node _to, std::size_t _act, std::string _label_of_action, bool _weak=false)
A header file defining a transition as a triple from,label,to.