DiaDes  0.1
DIAgnosis of Discrete-Event System
Minimize.hh
Go to the documentation of this file.
1 
9 #ifndef __DIADES__AUTOMATA__EXPERIMENTAL__MINIMIZE__HH
10 #define __DIADES__AUTOMATA__EXPERIMENTAL__MINIMIZE__HH
11 
12 #include<unordered_map>
13 #include<set>
22 
23 namespace Diades {
24  namespace Automata {
25  namespace Experimental {
26 
48  template<typename Fsm>
49  bool
50  splitPartition(const Fsm & machine,
51  const std::shared_ptr<BeliefState<Fsm>> bigQ0,
52  const std::shared_ptr<BeliefState<Fsm>> bigQ1,
53  typename Fsm::EventPropertyId littleA,
54  std::shared_ptr<BeliefState<Fsm>> bigQ0prime,
55  std::shared_ptr<BeliefState<Fsm>> bigQ0MinusbigQ0prime) {
56  bool result = true;
57  // first of all, if Q0 owns one state only, by definition it is not splittable
58  // especially if Q0 owns the sink state { represented by an empty belief state }
59  if (bigQ0->size() <= 1) {
60  result = false;
61  } else {
62  // two cases, either bigQ1 is empty (this is the sink state) or not (normal belief state)
63  for (auto state : bigQ0->setOfNodes()) {
64  auto transIt = machine.outputEventTransitionBegin(state, littleA);
65  if (transIt == machine.outputEventTransitionEnd(state, littleA)) {
66  // *transIt is actually the transition: 'state --littleA--> sinkState'
67  if (bigQ1->isEmpty()) {
68  bigQ0prime->insertNode(state);
69  } else {
70  bigQ0MinusbigQ0prime->insertNode(state);
71  }
72  } else {
73  // *transIt is a real transition from the machine: 'source --littleA--> target'
74  // and target is not the sink state
75  if (bigQ1->isEmpty()) {
76  bigQ0MinusbigQ0prime->insertNode(state);
77  } else {
78  // check whether transIt->target is in Q1 or not
79  if (bigQ1->findNode(transIt->target()) != bigQ1->end()) {
80  bigQ0prime->insertNode(state);
81  } else {
82  bigQ0MinusbigQ0prime->insertNode(state);
83  }
84  }
85  }
86 
87  if ((bigQ0->size() == bigQ0prime->size()) ||
88  (bigQ0->size() == bigQ0MinusbigQ0prime->size())) {
89  // Not splittable
90  bigQ0prime->setOfNodes().clear();
91  bigQ0MinusbigQ0prime->setOfNodes().clear();
92  result = false;
93  }
94  }
95  }
96  return result;
97  }
98 
112  template<typename Fsm>
113  void
114  nerodePartition(const Fsm & machine,
115  vector<std::shared_ptr<BeliefState<Fsm>>> & partition) {
116  using BelState = BeliefState<Fsm>;
117  using BelStatePtr = std::shared_ptr<BelState>;
118  using EventInfo = typename Fsm::EventPropertyId;
119  //using BsIterator = Diades::Utils::SharedPointerConstIterator<BelState, std::vector>;
120 
121 
122  // Now we are ready to apply the Hopcroft algorithm on the partition
123  // This algorithm is based on the description in
124  // "A taxonomy of finite automata minimization algorithms" by Bruce W. Watson
125  // watson@win.tue.nl
126  if (isComplete(machine)) {
127  // the machine is complete. As there is no notion of acceptor
128  // states in this version of the algorithm, it means that
129  // all the states are acceptors. It results that
130  // the minimal DFA in this case in simply the universal
131  // DFA (a partition of one elament with all the states in)
132  auto bs = std::make_shared<BelState>(machine);
133  bs->insertStates(machine.stateBegin(), machine.stateEnd());
134  partition.push_back(bs);
135  } else {
136  // The current DFA is not complete, we must use a sink state to apply the algorithm
137  // We won't complete the DFA explicitely but implicitly by the use of an empty
138  // BeliefState pointer. In this version, all the states are acceptors EXCEPT
139  // the sink state.
140  // Here partition represents variable P initialised with [ {non acceptor states}, {acceptor states} ]
141  auto sinkState = std::make_shared<BelState>(machine);
142  partition.push_back(sinkState); // I do not represent the sink state in the partition
143  auto allState = std::make_shared<BelState>(machine);
144  allState->insertStates(machine.stateBegin(), machine.stateEnd());
145  partition.push_back(allState);
146 
147 
148  // As the sink state is always part of a singleton in any
149  // computed partition, we start iterating with by putting in L
150  // L := sinkstate x letter1 , sinkstate x letter2, ....
151  std::unordered_map<EventInfo, std::set<BelStatePtr> > bigL;
152  // implements L: (Q,a) \in L iff bigL[a].find(Q) != bigL[a].end()
153  // initialise: L = F x V i.e {sinkState} x [eventBegin, eventEnd)
154  std::for_each(machine.eventBegin(), machine.eventEnd(),
155  [&](EventInfo e) {
156  bigL[e].insert(sinkState); });
157 
158 
159  while (!bigL.empty()) {
160  // Let (Q_1,a) : (Q_1,a) in L
161  EventInfo a = bigL.begin()->first;
162  BelStatePtr bigQ1 = *(bigL.begin()->second.begin());
163 
164 
165  // L:= L\{(Q_1,a)}
166  bigL.begin()->second.erase(bigL.begin()->second.begin());
167  if (bigL.begin()->second.empty()) {
168  bigL.erase(bigL.begin());
169  }
170 
171  size_t oldPartitionSize = partition.size(); // I dont copy to P_old, no need
172 
173  for (size_t index = 0; index < oldPartitionSize; ++index) // for Q_0 in P_old
174  {
175 
176  auto bigQ0 = partition[index];
177  auto bigQ0prime = std::make_shared<BelState>(machine);
178  auto bigQ0MinusbigQ0prime = std::make_shared<BelState>(machine);
179  if (splitPartition(machine, bigQ0, bigQ1, a, bigQ0prime, bigQ0MinusbigQ0prime)) {
180  // it means that Splittable(Q_0,Q_1,a) and bigQ0prime is not empty
181  partition[index] = bigQ0prime;
182  partition.push_back(bigQ0MinusbigQ0prime); // P = P \ {Q0} \cup {Q0\Q0',Q0'}
183 
184  for (auto littleB : machine.events()) {
185  auto & bss = bigL[littleB];
186  if (bss.find(bigQ0) != bss.end()) {
187 
188  bss.erase(bigQ0);
189  bss.insert(bigQ0prime);
190  bss.insert(bigQ0MinusbigQ0prime);
191  // L = L \ {(Q0,b)} \cup {(Q0',b), (Q0 \ Q0',b)}
192  } else {
193  if (bigQ0prime->size() <= bigQ0MinusbigQ0prime->size()) {
194  bss.insert(bigQ0prime);
195  } else {
196  bss.insert(bigQ0MinusbigQ0prime);
197  }
198  // L = L \cup {min( (Q0',b) , (Q0\Q0',b) ) }
199  }
200  }
201  }
202  }
203 
204  }
205  }
206  }
207 
208 
223  template<typename Fsm, typename StateCreator>
224  void
226  Fsm & minimalMachine,
227  StateCreator & creator) {
228  using Bs = BeliefState<Fsm>;
229  using BsPointer = std::shared_ptr < Bs >;
231  std::vector<BsPointer> partition;
232  // we compute the nerode partitition: i.e. the partition of states such that
233  // for any Q0 Q1 there is no pair of state q0 and q'0 from Q0 such
234  // that q0 - a -> q1 is a transition of 'machine' and q1 is in Q1
235  // while q'0 - a -> q'1 is a transition of 'machine' and q'1 is NOT in Q1
236  nerodePartition(machine, partition);
237  // once the partition is found, just abstract the machine
238  // be aware that there might an empty belief state at the beginning of
239  // partition (sink state)
240  auto partIt = partition.begin();
241  if ((*partIt)->isEmpty()) {
242  ++partIt;
243  }
244  abstract(machine, minimalMachine,
245  BsIterator(partIt),
246  BsIterator(partition.end()),
247  creator);
248  }
249 
250 
251 
252 
253 
254 // /**
255 // *
256 // * @param machine The original StateMachine
257 // * @param minimalMachine The minimal version of the original StateMachine
258 // * @pre minimalMachine must not be the original machine
259 // * @pre Note that if the StateMachine does not have any initial state, it is considered
260 // * as if the original StateMachine is empty. A StateMachine that has no
261 // * 'specific' initial states is a StateMachine such any state can be initial, in this case
262 // * machine.setAllInitialStates() must be applied first.
263 // * @pre machine must be deterministic (no check here)
264 // * @post A minimal StateMachine, if not empty, has one initial state only.
265 // */
266 // template<typename Fsm>
267 // void
268 // minimizeDeterministicMachine(const Fsm & machine,
269 // Fsm & minimalMachine) {
270 // using Bs = BeliefState<Fsm>;
271 // using BsPointer = std::shared_ptr < Bs >;
272 // using BsIterator = Diades::Utils::SharedPointerIterator<Bs, std::vector>;
273 // std::vector<BsPointer> partition;
274 // // we compute the nerode partitition: i.e. the partition of states such that
275 // // for any Q0 Q1 there is no pair of state q0 and q'0 from Q0 such
276 // // that q0 - a -> q1 is a transition of 'machine' and q1 is in Q1
277 // // while q'0 - a -> q'1 is a transition of 'machine' and q'1 is NOT in Q1
278 // nerodePartition(machine, partition);
279 // // once the partition is found, just abstract the machine
280 // // be aware that there might an empty belief state at the beginning of
281 // // partition (sink state)
282 // auto partIt = partition.begin();
283 // if ((*partIt)->isEmpty()) {
284 // ++partIt;
285 // }
286 // OnlyStateCreator<Fsm> creator(machine,minimalMachine);
287 // abstract(machine, minimalMachine,
288 // BsIterator(partIt),
289 // BsIterator(partition.end()),creator);
290 // }
291 
292 // /**
293 // *
294 // * @param machine The original StateMachine
295 // * @param minimalMachine The minimal version of the original StateMachine
296 // * @pre minimalMachine must not be the original machine
297 // * @pre Note that if the StateMachine does not have any initial state, it is considered
298 // * as if the original StateMachine is empty. A StateMachine that has no
299 // * 'specific' initial states is a StateMachine such any state can be initial, in this case
300 // * machine.setAllInitialStates() must be applied first.
301 // * @post A minimal StateMachine, if not empty, has one initial state only.
302 // */
303 // template<typename Fsm>
304 // void
305 // minimize(const Fsm & machine,
306 // Fsm & minimalMachine) {
307 // if (machine.numberOfInitialStates() == 0) {
308 // minimalMachine.clear();
309 // } else {
310 // if (!isDeterministic(machine)) {
311 // // the Hopcroft minimization algorithm only works on deterministic machines
312 // Fsm deterministicMachine;
313 // OnlyStateCreator<Fsm> creator(machine,deterministicMachine);
314 // determine(machine, deterministicMachine,creator);
315 // minimizeDeterministicMachine(deterministicMachine, minimalMachine);
316 // } else {
317 // minimizeDeterministicMachine(machine, minimalMachine);
318 // }
319 // }
320 // }
321 
322 
334  template<typename Fsm, typename StateCreator>
335  void
336  minimize(const Fsm & machine,
337  Fsm & minimalMachine,
338  StateCreator & creator) {
339  if (machine.numberOfInitialStates() == 0) {
340  minimalMachine.clear();
341  } else {
342  if(!isDeterministic(machine))
343  {
344  return;
345  }
346  else
347  {
349  minimalMachine,
350  creator);
351 
352  }
353  }
354  }
355 
356 
357  }
358  }
359 }
360 
361 
362 #endif /* __DIADES__AUTOMATA__EXPERIMENTAL__MINIMIZE__HH */
363 
FaultyEventStateMachine< CandidateId, EventInfoId > Fsm
void nerodePartition(const Fsm &machine, vector< std::shared_ptr< BeliefState< Fsm >>> &partition)
Definition: Minimize.hh:114
void minimizeDeterministicMachine(const Fsm &machine, Fsm &minimalMachine, StateCreator &creator)
Definition: Minimize.hh:225
Namespace of the Diades project.
bool isComplete(const Fsm &machine)
Definition: Complete.hh:36
void minimize(const Fsm &machine, Fsm &minimalMachine, StateCreator &creator)
Definition: Minimize.hh:336
bool isDeterministic(const Fsm &machine)
Definition: Determine.hh:35
bool splitPartition(const Fsm &machine, const std::shared_ptr< BeliefState< Fsm >> bigQ0, const std::shared_ptr< BeliefState< Fsm >> bigQ1, typename Fsm::EventPropertyId littleA, std::shared_ptr< BeliefState< Fsm >> bigQ0prime, std::shared_ptr< BeliefState< Fsm >> bigQ0MinusbigQ0prime)
Definition: Minimize.hh:50