omg_pseudodet.cpp
Go to the documentation of this file.
1 /** @file omg_pseudodet.cpp
2  *
3  * Implementation of pseudo-determinization algorithm for Rabin automata
4  * Strictly follows the paper algorithm with fixed node numbering
5  */
6 
7 #include "libfaudes.h"
8 #include "omg_pseudodet.h"
9 
10 namespace faudes {
11 
12 /*
13 ********************************
14 Enhanced State Implementation
15 ********************************
16 */
17 
18 EnhancedState::EnhancedState() : originalState(0) {}
19 
20 bool EnhancedState::operator<(const EnhancedState& other) const {
21  if(originalState != other.originalState) return originalState < other.originalState;
23 }
24 
25 bool EnhancedState::operator==(const EnhancedState& other) const {
26  return originalState == other.originalState &&
28 }
29 
30 std::string EnhancedState::ToString() const {
31  std::ostringstream oss;
32  oss << "EnhancedState{original=" << originalState << ", deleted=[";
33  for(int nodeNum : deletedNodesInPrevStep) {
34  oss << nodeNum << ",";
35  }
36  oss << "]}";
37  return oss.str();
38 }
39 
40 /*
41 ********************************
42 TreeNode Implementation
43 ********************************
44 */
45 
46 TreeNode::TreeNode() : nodeNumber(-1), color(WHITE) {}
47 
48 TreeNode::TreeNode(int number) : nodeNumber(number), color(WHITE) {}
49 
50 bool TreeNode::operator<(const TreeNode& other) const {
51  if(nodeNumber != other.nodeNumber) return nodeNumber < other.nodeNumber;
52  if(stateLabel != other.stateLabel) return stateLabel < other.stateLabel;
53  if(aSet != other.aSet) return aSet < other.aSet;
54  if(rSet != other.rSet) return rSet < other.rSet;
55  if(children != other.children) return children < other.children;
56  return color < other.color;
57 }
58 
59 bool TreeNode::operator==(const TreeNode& other) const {
60  return nodeNumber == other.nodeNumber &&
61  stateLabel == other.stateLabel &&
62  aSet == other.aSet &&
63  rSet == other.rSet &&
64  children == other.children &&
65  color == other.color;
66 }
67 
68 std::string TreeNode::ToString() const {
69  std::ostringstream oss;
70  oss << "Node{num=" << nodeNumber << ", states=[" << stateLabel.ToString() << "], ";
71  oss << "color=" << (color == WHITE ? "WHITE" : (color == RED ? "RED" : "GREEN")) << ", ";
72  oss << "children=" << children.size() << ", ";
73  oss << "aSet=" << aSet.size() << ", ";
74  oss << "rSet=" << rSet.size() << "}";
75  return oss.str();
76 }
77 
78 /*
79 ********************************
80 LabeledTree Implementation
81 ********************************
82 */
83 
84 LabeledTree::LabeledTree() : rootNode(LabeledTree::INVALID_NODE), nextNodeId(1), maxNodeCount(0) {}
85 
86 LabeledTree::LabeledTree(int N) : rootNode(LabeledTree::INVALID_NODE), nextNodeId(1), maxNodeCount(N) {
87  nodeNumberUsed.resize(N + 1, false); // Index 0 unused, 1..N available
88 }
89 
91  if(nodeNumber < 1 || nodeNumber > maxNodeCount) {
92  throw Exception("LabeledTree::createNodeWithNumber",
93  "Invalid node number " + ToStringInteger(nodeNumber), 500);
94  }
95 
96  if(nodeNumberUsed[nodeNumber]) {
97  throw Exception("LabeledTree::createNodeWithNumber",
98  "Node number " + ToStringInteger(nodeNumber) + " already used", 500);
99  }
100 
101  Idx newId = nextNodeId++;
102  nodes[newId] = TreeNode(nodeNumber);
103  numberToId[nodeNumber] = newId;
104  idToNumber[newId] = nodeNumber;
105  nodeNumberUsed[nodeNumber] = true;
106 
107  return newId;
108 }
109 
111  // Find first available node number
112  for(int i = 1; i <= maxNodeCount; ++i) {
113  if(!nodeNumberUsed[i]) {
114  return createNodeWithNumber(i);
115  }
116  }
117 
118  throw Exception("LabeledTree::createNode",
119  "No available node numbers (max=" + ToStringInteger(maxNodeCount) + ")", 500);
120 }
121 
123  if(nodes.find(nodeId) == nodes.end()) return;
124 
125  int nodeNumber = idToNumber[nodeId];
126 
127  // Remove this node from all parent children lists
128  for(auto& pair : nodes) {
129  TreeNode& node = pair.second;
130  auto it = std::find(node.children.begin(), node.children.end(), nodeId);
131  if(it != node.children.end()) {
132  node.children.erase(it);
133  }
134 
135  // Remove from A-sets and R-sets (use node numbers)
136  node.aSet.erase(nodeNumber);
137  node.rSet.erase(nodeNumber);
138  }
139 
140  // Clean up mappings
141  numberToId.erase(nodeNumber);
142  idToNumber.erase(nodeId);
143  nodeNumberUsed[nodeNumber] = false;
144  deletedNodeNumbers.insert(nodeNumber);
145 
146  nodes.erase(nodeId);
147 }
148 
149 int LabeledTree::getNodeNumber(Idx nodeId) const {
150  auto it = idToNumber.find(nodeId);
151  return (it != idToNumber.end()) ? it->second : -1;
152 }
153 
154 Idx LabeledTree::getNodeId(int nodeNumber) const {
155  auto it = numberToId.find(nodeNumber);
156  return (it != numberToId.end()) ? it->second : LabeledTree::INVALID_NODE;
157 }
158 
159 bool LabeledTree::hasNodeNumber(int nodeNumber) const {
160  return numberToId.find(nodeNumber) != numberToId.end();
161 }
162 
163 std::string LabeledTree::ToString() const {
164  std::ostringstream oss;
165  oss << "Tree{root=" << rootNode << "(num=" << getNodeNumber(rootNode) << "), nodes=[";
166  for(auto& pair : nodes) {
167  oss << pair.first << ":" << pair.second.ToString() << ", ";
168  }
169  oss << "], deleted=[";
170  for(int nodeNum : deletedNodeNumbers) {
171  oss << nodeNum << ",";
172  }
173  oss << "]}";
174  return oss.str();
175 }
176 
177 bool LabeledTree::operator<(const LabeledTree& other) const {
178  if(rootNode != other.rootNode) return rootNode < other.rootNode;
180  return nodes < other.nodes;
181 }
182 
183 bool LabeledTree::operator==(const LabeledTree& other) const {
184  if(rootNode != other.rootNode) return false;
185  if(deletedNodeNumbers != other.deletedNodeNumbers) return false;
186  if(nodes.size() != other.nodes.size()) return false;
187 
188  for(auto it1 = nodes.begin(), it2 = other.nodes.begin();
189  it1 != nodes.end() && it2 != other.nodes.end(); ++it1, ++it2) {
190  if(it1->first != it2->first) return false;
191  if(!(it1->second == it2->second)) return false;
192  }
193 
194  return true;
195 }
196 
197 /*
198 ********************************
199 Helper Functions
200 ********************************
201 */
202 
203 std::string ComputeTreeSignature(const LabeledTree& tree, const std::set<int>& deletedNodes) {
204  std::ostringstream oss;
205 
206  // Include deleted nodes in signature
207  oss << "deleted:[";
208  for(int nodeNum : deletedNodes) {
209  oss << nodeNum << ",";
210  }
211  oss << "];";
212 
213  // Recursive signature processing using node numbers
214  std::function<void(Idx)> dfs = [&](Idx nodeId) {
215  if(tree.nodes.find(nodeId) == tree.nodes.end()) return;
216 
217  const TreeNode& node = tree.nodes.at(nodeId);
218  oss << "n" << node.nodeNumber << ":";
219  oss << node.stateLabel.ToString() << ":";
220  oss << static_cast<int>(node.color) << ":";
221 
222  // Process children in node number order for consistency
223  std::vector<std::pair<int, Idx>> childrenWithNumbers;
224  for(Idx childId : node.children) {
225  if(tree.nodes.find(childId) != tree.nodes.end()) {
226  childrenWithNumbers.push_back({tree.getNodeNumber(childId), childId});
227  }
228  }
229  std::sort(childrenWithNumbers.begin(), childrenWithNumbers.end());
230 
231  for(auto& child : childrenWithNumbers) {
232  dfs(child.second);
233  }
234 
235  oss << ";";
236  };
237 
238  dfs(tree.rootNode);
239  return oss.str();
240 }
241 
242 /*
243 ********************************
244 Main Algorithm Implementation - PAPER COMPLIANT
245 ********************************
246 */
247 
248 void PseudoDet(const RabinAutomaton& rGen, RabinAutomaton& rRes) {
249  FD_DF("PseudoDet(" << rGen.Name() << ") - Paper Algorithm");
250 
251  // Get input Rabin automaton acceptance condition
252  RabinAcceptance inputRabinPairs = rGen.RabinAcceptance();
253 
254  rRes.Clear();
255  rRes.Name(CollapsString("PseudoDet(" + rGen.Name() + ")"));
256 
257  // Copy alphabet
258  rRes.InjectAlphabet(rGen.Alphabet());
259 
260  // Safety limits
261  const int MAX_STATES = 100000;
262  const int MAX_ITERATIONS = 100000;
263  int stateCounter = 0;
264  int iterationCounter = 0;
265 
266  // Fixed number of nodes N = |Xv| as per paper
267  const int N = 10*rGen.Size();
268  FD_DF("Using N = " << N << " fixed nodes");
269 
270  // Enhanced state tracking: map enhanced state -> tree
271  std::map<EnhancedState, LabeledTree> enhancedStateToTree;
272 
273  // Track tree signatures
274  std::map<std::string, EnhancedState> treeSignatureToEnhancedState;
275 
276  // Create initial tree with fixed node count
277  LabeledTree initialTree(N);
278  Idx root = initialTree.createNodeWithNumber(1); // Root is always node number 1
279  initialTree.rootNode = root;
280 
281  // Set root node label to contain all initial states
282  for(StateSet::Iterator sit = rGen.InitStatesBegin(); sit != rGen.InitStatesEnd(); ++sit) {
283  initialTree.nodes[root].stateLabel.Insert(*sit);
284  }
285 
286  // Create initial enhanced state
287  EnhancedState initialEnhancedState;
288  initialEnhancedState.originalState = rRes.InsInitState();
289  // No deleted nodes initially
290 
291  enhancedStateToTree[initialEnhancedState] = initialTree;
292 
293  std::string initialSig = ComputeTreeSignature(initialTree, initialEnhancedState.deletedNodesInPrevStep);
294  treeSignatureToEnhancedState[initialSig] = initialEnhancedState;
295 
296  std::queue<EnhancedState> stateQueue;
297  stateQueue.push(initialEnhancedState);
298  stateCounter++;
299 
300  // Process all states
301  while(!stateQueue.empty() && stateCounter < MAX_STATES && iterationCounter < MAX_ITERATIONS) {
302  iterationCounter++;
303 
304  EnhancedState currentEnhancedState = stateQueue.front();
305  stateQueue.pop();
306 
307  LabeledTree currentTree = enhancedStateToTree[currentEnhancedState];
308  FD_DF("Processing enhanced state " << currentEnhancedState.ToString()
309  << " with tree: " << currentTree.ToString());
310 
311  // Process each event
312  for(EventSet::Iterator evIt = rGen.AlphabetBegin(); evIt != rGen.AlphabetEnd(); ++evIt) {
313  Idx event = *evIt;
314  FD_DF("Processing event " << rGen.EventName(event));
315 
316  // Clone tree with same node count
317  LabeledTree newTree(N);
319 
320  // Copy existing nodes with their numbers
321  for(auto& pair : currentTree.nodes) {
322  Idx oldId = pair.first;
323  TreeNode& oldNode = pair.second;
324 
325  Idx newId = newTree.createNodeWithNumber(oldNode.nodeNumber);
326  newTree.nodes[newId] = oldNode;
327  newTree.nodes[newId].children.clear(); // Will rebuild children relationships
328 
329  if(oldId == currentTree.rootNode) {
330  newTree.rootNode = newId;
331  }
332  }
333 
334  // Rebuild parent-child relationships
335  for(auto& pair : currentTree.nodes) {
336  Idx oldParentId = pair.first;
337  TreeNode& oldParent = pair.second;
338  int parentNumber = oldParent.nodeNumber;
339 
340  Idx newParentId = newTree.getNodeId(parentNumber);
341  if(newParentId == LabeledTree::INVALID_NODE) continue;
342 
343  for(Idx oldChildId : oldParent.children) {
344  if(currentTree.nodes.find(oldChildId) == currentTree.nodes.end()) continue;
345 
346  int childNumber = currentTree.nodes[oldChildId].nodeNumber;
347  Idx newChildId = newTree.getNodeId(childNumber);
348 
349  if(newChildId != LabeledTree::INVALID_NODE) {
350  newTree.nodes[newParentId].children.push_back(newChildId);
351  }
352  }
353  }
354 
355  // Track deleted nodes from this step
356  std::set<int> deletedInThisStep;
357 
358  // STEP 1: Color all nodes white
359  for(auto& pair : newTree.nodes) {
360  pair.second.color = TreeNode::WHITE;
361  }
362 
363  // STEP 2: Update state labels based on transitions
364  std::string eventName = rGen.EventName(event);
365  bool isEpsilonEvent = (eventName == "eps");
366 
367  if (isEpsilonEvent) {
368  // Case 2a: If σ_c = ε, replace every state label Y with δ_v(ε, Y) ∪ Y
369  for(auto& pair : newTree.nodes) {
370  TreeNode& node = pair.second;
371  StateSet newLabel = node.stateLabel; // Start with Y
372 
373  // Add δ_v(ε, Y)
374  for(StateSet::Iterator sit = node.stateLabel.Begin(); sit != node.stateLabel.End(); ++sit) {
375  Idx state = *sit;
376  for(TransSet::Iterator tit = rGen.TransRelBegin(state, event);
377  tit != rGen.TransRelEnd(state, event); ++tit) {
378  newLabel.Insert(tit->X2);
379  }
380  }
381  node.stateLabel = newLabel;
382  }
383  } else {
384  // Case 2b: Check epsilon closure condition
385  if(newTree.rootNode == LabeledTree::INVALID_NODE) {
386  continue; // No root, skip
387  }
388 
389  StateSet rootLabel = newTree.nodes[newTree.rootNode].stateLabel;
390  StateSet epsilonSuccessors;
391 
392  // Compute δ_v(ε, Y_r)
393  for(StateSet::Iterator sit = rootLabel.Begin(); sit != rootLabel.End(); ++sit) {
394  Idx state = *sit;
395  for(EventSet::Iterator eit = rGen.AlphabetBegin(); eit != rGen.AlphabetEnd(); ++eit) {
396  std::string eName = rGen.EventName(*eit);
397  if(eName == "eps") {
398  for(TransSet::Iterator tit = rGen.TransRelBegin(state, *eit);
399  tit != rGen.TransRelEnd(state, *eit); ++tit) {
400  epsilonSuccessors.Insert(tit->X2);
401  }
402  }
403  }
404  }
405 
406  // Check if Y_r ⊇ δ_v(ε, Y_r)
407  bool conditionSatisfied = true;
408  for(StateSet::Iterator sit = epsilonSuccessors.Begin(); sit != epsilonSuccessors.End(); ++sit) {
409  if(!rootLabel.Exists(*sit)) {
410  conditionSatisfied = false;
411  break;
412  }
413  }
414 
415  if(conditionSatisfied) {
416  // Replace every state label Y with δ_v(σ_c, Y)
417  for(auto& pair : newTree.nodes) {
418  TreeNode& node = pair.second;
419  StateSet newLabel;
420 
421  for(StateSet::Iterator sit = node.stateLabel.Begin(); sit != node.stateLabel.End(); ++sit) {
422  Idx state = *sit;
423  for(TransSet::Iterator tit = rGen.TransRelBegin(state, event);
424  tit != rGen.TransRelEnd(state, event); ++tit) {
425  newLabel.Insert(tit->X2);
426  }
427  }
428  node.stateLabel = newLabel;
429  }
430  } else {
431  // Transition function is undefined, skip this event
432  continue;
433  }
434  }
435 
436  // STEP 3: Create nodes for Rabin acceptance violations
437  // Use single I set (first Rabin pair) as per paper assumption
438  if(inputRabinPairs.Size() > 0) {
439  const StateSet& Iv = inputRabinPairs.Begin()->ISet();
440 
441  // Create copy of current nodes to iterate over
442  std::vector<std::pair<Idx, TreeNode>> currentNodes;
443  for(auto& pair : newTree.nodes) {
444  currentNodes.push_back(pair);
445  }
446 
447  for(auto& nodePair : currentNodes) {
448  Idx nodeId = nodePair.first;
449  TreeNode& node = newTree.nodes[nodeId];
450 
451  // Compute Y ∩ (Xv \ Iv)
452  StateSet intersectionWithoutI;
453  for(StateSet::Iterator sit = node.stateLabel.Begin();
454  sit != node.stateLabel.End(); ++sit) {
455  if(!Iv.Exists(*sit)) {
456  intersectionWithoutI.Insert(*sit);
457  }
458  }
459 
460  // If Y ∩ (Xv \ Iv) ≠ ∅, create red child
461  if(!intersectionWithoutI.Empty()) {
462  try {
463  Idx newChild = newTree.createNode();
464  newTree.nodes[newChild].stateLabel = intersectionWithoutI;
465  newTree.nodes[newChild].color = TreeNode::RED;
466  newTree.nodes[newChild].aSet.clear();
467  newTree.nodes[newChild].rSet.clear();
468  node.children.push_back(newChild);
469 
470  FD_DF("Created RED child node " << newChild
471  << " (number " << newTree.getNodeNumber(newChild) << ") for node " << nodeId);
472  } catch(Exception& e) {
473  FD_DF("Warning: Could not create child node - " << e.What());
474  // Continue without creating child if no node numbers available
475  }
476  }
477  }
478  }
479 
480  // STEP 4: Maintain state disjointness among siblings
481  for(auto& pair : newTree.nodes) {
482  Idx parentId = pair.first;
483  TreeNode& parent = pair.second;
484 
485  // For each child, remove states that appear in older siblings
486  for(size_t i = 1; i < parent.children.size(); ++i) {
487  Idx youngerId = parent.children[i];
488 
489  if(newTree.nodes.find(youngerId) == newTree.nodes.end()) continue;
490 
491  // Check all older siblings
492  for(size_t j = 0; j < i; ++j) {
493  Idx olderId = parent.children[j];
494 
495  if(newTree.nodes.find(olderId) == newTree.nodes.end()) continue;
496 
497  // Remove states from younger sibling and ALL its descendants
498  std::vector<Idx> toProcess;
499  toProcess.push_back(youngerId);
500 
501  while(!toProcess.empty()) {
502  Idx currentId = toProcess.back();
503  toProcess.pop_back();
504 
505  if(newTree.nodes.find(currentId) == newTree.nodes.end()) continue;
506 
507  TreeNode& currentNode = newTree.nodes[currentId];
508 
509  // Remove states that appear in older sibling
510  for(StateSet::Iterator sit = newTree.nodes[olderId].stateLabel.Begin();
511  sit != newTree.nodes[olderId].stateLabel.End(); ++sit) {
512  currentNode.stateLabel.Erase(*sit);
513  }
514 
515  // Add children to processing queue
516  for(Idx childId : currentNode.children) {
517  toProcess.push_back(childId);
518  }
519  }
520  }
521  }
522  }
523 
524  // STEP 5: Remove all nodes with empty state labels
525  std::vector<Idx> nodesToRemove;
526  for(auto& pair : newTree.nodes) {
527  if(pair.second.stateLabel.Empty()) {
528  nodesToRemove.push_back(pair.first);
529  }
530  }
531 
532  for(Idx nodeId : nodesToRemove) {
533  int nodeNumber = newTree.getNodeNumber(nodeId);
534  deletedInThisStep.insert(nodeNumber);
535  newTree.deleteNode(nodeId);
536  }
537 
538  // STEP 6: Determine red breakpoints
539  for(auto& pair : newTree.nodes) {
540  Idx nodeId = pair.first;
541  TreeNode& node = pair.second;
542 
543  // Compute union of children's state labels
544  StateSet unionOfChildren;
545  for(Idx childId : node.children) {
546  if(newTree.nodes.find(childId) == newTree.nodes.end()) continue;
547 
548  for(StateSet::Iterator sit = newTree.nodes[childId].stateLabel.Begin();
549  sit != newTree.nodes[childId].stateLabel.End(); ++sit) {
550  unionOfChildren.Insert(*sit);
551  }
552  }
553 
554  if(node.stateLabel == unionOfChildren && !unionOfChildren.Empty()) {
555  FD_DF("Red breakpoint at node " << nodeId);
556  node.color = TreeNode::RED;
557 
558  // Delete all descendants and record their numbers
559  std::vector<Idx> descendants;
560  std::queue<Idx> bfs;
561  for(Idx child : node.children) {
562  if(newTree.nodes.find(child) != newTree.nodes.end()) {
563  bfs.push(child);
564  }
565  }
566 
567  while(!bfs.empty()) {
568  Idx current = bfs.front();
569  bfs.pop();
570  descendants.push_back(current);
571 
572  if(newTree.nodes.find(current) == newTree.nodes.end()) continue;
573  for(Idx child : newTree.nodes[current].children) {
574  if(newTree.nodes.find(child) != newTree.nodes.end()) {
575  bfs.push(child);
576  }
577  }
578  }
579 
580  for(Idx descendant : descendants) {
581  int nodeNumber = newTree.getNodeNumber(descendant);
582  deletedInThisStep.insert(nodeNumber);
583  newTree.deleteNode(descendant);
584  }
585 
586  node.children.clear();
587  node.aSet.clear();
588  node.rSet.clear();
589  }
590  }
591 
592  // STEP 7: Delete the nodes removed in the above two steps from the A- and R-sets of all other nodes
593  // (This is already handled by deleteNode method which uses node numbers)
594 
595  // STEP 8: If the A-set of a node n is empty and n is not colored red, then color n green
596  // and set its A-set equal to its R-set. Then let its R-set be empty.
597  for(auto& pair : newTree.nodes) {
598  Idx nodeId = pair.first;
599  TreeNode& node = pair.second;
600 
601  if(node.aSet.empty() && node.color != TreeNode::RED) {
602  FD_DF("Green coloring for node " << nodeId << " (number " << node.nodeNumber << ")");
603  node.color = TreeNode::GREEN;
604  node.aSet = node.rSet;
605  node.rSet.clear();
606  }
607  }
608 
609  // STEP 9: If a node is not colored red, then add to its R-set the set of all other nodes
610  // presently colored red (using node numbers).
611  std::set<int> redNodeNumbers;
612  for(auto& pair : newTree.nodes) {
613  if(pair.second.color == TreeNode::RED) {
614  redNodeNumbers.insert(pair.second.nodeNumber);
615  }
616  }
617 
618  for(auto& pair : newTree.nodes) {
619  if(pair.second.color != TreeNode::RED) {
620  for(int redNodeNumber : redNodeNumbers) {
621  pair.second.rSet.insert(redNodeNumber);
622  }
623  }
624  }
625 
626  // Create enhanced target state
627  EnhancedState targetEnhancedState;
628  targetEnhancedState.deletedNodesInPrevStep = deletedInThisStep;
629 
630  // Check if this tree was seen before
631  std::string treeSig = ComputeTreeSignature(newTree, deletedInThisStep);
632 
633  auto stateIt = treeSignatureToEnhancedState.find(treeSig);
634  if(stateIt != treeSignatureToEnhancedState.end()) {
635  // If so, use existing enhanced state
636  targetEnhancedState = stateIt->second;
637  FD_DF("Found existing enhanced state " << targetEnhancedState.ToString() << " for tree");
638  } else {
639  // Create new state for this tree
640  targetEnhancedState.originalState = rRes.InsState();
641  enhancedStateToTree[targetEnhancedState] = newTree;
642  treeSignatureToEnhancedState[treeSig] = targetEnhancedState;
643 
644  stateQueue.push(targetEnhancedState);
645  stateCounter++;
646 
647  FD_DF("Created new enhanced state " << targetEnhancedState.ToString() << " for tree");
648  }
649 
650  // Add transition from current state to target state
651  rRes.SetTransition(currentEnhancedState.originalState, event, targetEnhancedState.originalState);
652  }
653  }
654 
655  if(stateCounter >= MAX_STATES) {
656  FD_DF("Warning: Reached maximum state limit of " << MAX_STATES);
657  }
658 
659  if(iterationCounter >= MAX_ITERATIONS) {
660  FD_DF("Warning: Reached maximum iteration limit of " << MAX_ITERATIONS);
661  }
662 
663  // Create Rabin pairs for output automaton - PAPER ALGORITHM
664  // "for every n, 1 ≤ n ≤ N, let Rn be the set of states in which node n is colored green in the tree
665  // and let In be the set of trees in which node n is not colored red in the tree and node n has not just been deleted from the tree."
666 
667  RabinAcceptance outputRabinPairs;
668 
669  // For each fixed node number 1 to N
670  for(int nodeNumber = 1; nodeNumber <= N; ++nodeNumber) {
671  StateSet Rn; // States where node n is colored green
672  StateSet In; // States where node n is not colored red and not just deleted
673 
674  // Iterate through all enhanced states
675  for(const auto& enhancedStatePair : enhancedStateToTree) {
676  const EnhancedState& enhancedState = enhancedStatePair.first;
677  const LabeledTree& tree = enhancedStatePair.second;
678  Idx state = enhancedState.originalState;
679 
680  // Check if node n exists in this tree
681  bool nodeExists = tree.hasNodeNumber(nodeNumber);
682 
683  // Check if node n was just deleted in previous step
684  bool nodeJustDeleted = enhancedState.deletedNodesInPrevStep.find(nodeNumber) !=
685  enhancedState.deletedNodesInPrevStep.end();
686 
687  if(nodeExists) {
688  Idx nodeId = tree.getNodeId(nodeNumber);
689  const TreeNode& node = tree.nodes.at(nodeId);
690 
691  // Populate In: node exists, not red, and not just deleted
692  if(node.color != TreeNode::RED && !nodeJustDeleted) {
693  In.Insert(state);
694  }
695 
696  // Populate Rn: node is green
697  if(node.color == TreeNode::GREEN) {
698  Rn.Insert(state);
699  }
700  } else {
701  // Node doesn't exist (was deleted in some previous step)
702  // It's not in In because it doesn't exist
703  // It's not in Rn because it can't be green if it doesn't exist
704  }
705  }
706 
707  // Add Rabin pair only if Rn is not empty
708  // (According to paper: meaningful pairs where infinite green visits can happen)
709  if(!Rn.Empty()) {
710  RabinPair newPair;
711  newPair.RSet() = Rn;
712  newPair.ISet() = In;
713  outputRabinPairs.Insert(newPair);
714 
715  FD_DF("Created Rabin pair for node " << nodeNumber
716  << ": R=" << Rn.Size() << " states, I=" << In.Size() << " states");
717  }
718  }
719 
720  rRes.RabinAcceptance() = outputRabinPairs;
721 
722  FD_DF("PseudoDet completed with "
723  << stateCounter << " states and "
724  << outputRabinPairs.Size() << " Rabin pairs");
725 }
726 
727 /*
728 ********************************
729 RemoveEps Implementation
730 ********************************
731 */
732 
733 void RemoveEps(const RabinAutomaton& rGen, RabinAutomaton& rRes) {
734  FD_DF("RemoveEps(" << rGen.Name() << ") - Two-phase approach");
735 
736  // Find epsilon event
737  Idx epsEvent = 0;
738  for(EventSet::Iterator evIt = rGen.AlphabetBegin(); evIt != rGen.AlphabetEnd(); ++evIt) {
739  std::string eventName = rGen.EventName(*evIt);
740  if(eventName == "eps") {
741  epsEvent = *evIt;
742  break;
743  }
744  }
745 
746  if(epsEvent == 0) {
747  FD_DF("No epsilon event found, copying automaton as-is");
748  rRes = rGen;
749  return;
750  }
751 
752  // Phase 1: Start with a copy and process eps-only states (relink)
753  rRes = rGen;
754 
755  bool changed = true;
756  while(changed) {
757  changed = false;
758 
759  // Find a state that has ONLY eps outgoing transitions (excluding self-loops)
760  for(StateSet::Iterator sit = rRes.StatesBegin(); sit != rRes.StatesEnd(); ++sit) {
761  Idx sourceState = *sit;
762 
763  std::vector<Transition> nonEpsOutgoing;
764  std::vector<Transition> epsNonSelfLoop;
765 
766  // Classify outgoing transitions
767  for(TransSet::Iterator tit = rRes.TransRelBegin(sourceState);
768  tit != rRes.TransRelEnd(sourceState); ++tit) {
769  if(tit->Ev == epsEvent) {
770  if(tit->X1 != tit->X2) { // Not a self-loop
771  epsNonSelfLoop.push_back(*tit);
772  }
773  // Ignore eps self-loops for now
774  } else {
775  nonEpsOutgoing.push_back(*tit);
776  }
777  }
778 
779  // Check if this state has ONLY one non-self-loop eps transition
780  if(nonEpsOutgoing.empty() && epsNonSelfLoop.size() == 1) {
781  Idx targetState = epsNonSelfLoop[0].X2;
782 
783  FD_DF("State " << sourceState << " has only eps transition to "
784  << targetState << " - relinking all inputs");
785 
786  // Find all incoming transitions to sourceState
787  std::vector<Transition> incomingTrans;
788  for(TransSet::Iterator tit = rRes.TransRelBegin();
789  tit != rRes.TransRelEnd(); ++tit) {
790  if(tit->X2 == sourceState) {
791  incomingTrans.push_back(*tit);
792  }
793  }
794 
795  // Relink all incoming transitions to targetState
796  for(const auto& incoming : incomingTrans) {
797  FD_DF("Relinking " << incoming.X1 << " --"
798  << rRes.EventName(incoming.Ev) << "--> "
799  << sourceState << " to " << incoming.X1
800  << " --" << rRes.EventName(incoming.Ev)
801  << "--> " << targetState);
802 
803  // Remove old transition
804  rRes.ClrTransition(incoming.X1, incoming.Ev, sourceState);
805 
806  // Add new transition (check for duplicates)
807  if(!rRes.ExistsTransition(incoming.X1, incoming.Ev, targetState)) {
808  rRes.SetTransition(incoming.X1, incoming.Ev, targetState);
809  }
810  }
811 
812  // Remove the eps transition from sourceState to targetState
813  rRes.ClrTransition(sourceState, epsEvent, targetState);
814 
815  // Handle initial states
816  if(rRes.ExistsInitState(sourceState)) {
817  rRes.ClrInitState(sourceState);
818  rRes.SetInitState(targetState);
819  FD_DF("Redirected initial state from " << sourceState << " to " << targetState);
820  }
821 
822  // Handle marked states
823  if(rRes.ExistsMarkedState(sourceState)) {
824  rRes.ClrMarkedState(sourceState);
825  rRes.SetMarkedState(targetState);
826  FD_DF("Redirected marked state from " << sourceState << " to " << targetState);
827  }
828 
829  // Update Rabin acceptance condition
830  RabinAcceptance currentRabin = rRes.RabinAcceptance();
831  RabinAcceptance newRabin;
832 
833  for(RabinAcceptance::Iterator rit = currentRabin.Begin(); rit != currentRabin.End(); ++rit) {
834  StateSet newR = rit->RSet();
835  StateSet newI = rit->ISet();
836 
837  // Replace sourceState with targetState in R set
838  if(newR.Exists(sourceState)) {
839  newR.Erase(sourceState);
840  newR.Insert(targetState);
841  }
842 
843  // Replace sourceState with targetState in I set
844  if(newI.Exists(sourceState)) {
845  newI.Erase(sourceState);
846  newI.Insert(targetState);
847  }
848 
849  RabinPair newPair;
850  newPair.RSet() = newR;
851  newPair.ISet() = newI;
852  newRabin.Insert(newPair);
853  }
854 
855  rRes.RabinAcceptance() = newRabin;
856 
857  changed = true;
858  break; // Restart to find next eps-only state
859  }
860  }
861  }
862 
863  // Phase 2: Remove all eps self-loops
864  FD_DF("Phase 2: Removing all eps self-loops");
865 
866  std::vector<Transition> selfLoopsToRemove;
867  for(TransSet::Iterator tit = rRes.TransRelBegin(); tit != rRes.TransRelEnd(); ++tit) {
868  if(tit->Ev == epsEvent && tit->X1 == tit->X2) {
869  selfLoopsToRemove.push_back(*tit);
870  }
871  }
872 
873  for(const auto& selfLoop : selfLoopsToRemove) {
874  FD_DF("Removing eps self-loop at state " << selfLoop.X1);
875  rRes.ClrTransition(selfLoop.X1, epsEvent, selfLoop.X2);
876  }
877 
878  // Remove unreachable states
879  StateSet reachableStates;
880  std::queue<Idx> stateQueue;
881 
882  // Start from initial states
883  for(StateSet::Iterator sit = rRes.InitStatesBegin(); sit != rRes.InitStatesEnd(); ++sit) {
884  if(!reachableStates.Exists(*sit)) {
885  reachableStates.Insert(*sit);
886  stateQueue.push(*sit);
887  }
888  }
889 
890  // BFS to find all reachable states
891  while(!stateQueue.empty()) {
892  Idx current = stateQueue.front();
893  stateQueue.pop();
894 
895  for(TransSet::Iterator tit = rRes.TransRelBegin(current);
896  tit != rRes.TransRelEnd(current); ++tit) {
897  if(!reachableStates.Exists(tit->X2)) {
898  reachableStates.Insert(tit->X2);
899  stateQueue.push(tit->X2);
900  }
901  }
902  }
903 
904  // Remove unreachable states
905  StateSet statesToRemove;
906  for(StateSet::Iterator sit = rRes.StatesBegin(); sit != rRes.StatesEnd(); ++sit) {
907  if(!reachableStates.Exists(*sit)) {
908  statesToRemove.Insert(*sit);
909  }
910  }
911 
912  for(StateSet::Iterator sit = statesToRemove.Begin(); sit != statesToRemove.End(); ++sit) {
913  rRes.DelState(*sit);
914  FD_DF("Removed unreachable state " << *sit);
915  }
916 
917  // Check if we still have eps transitions
918  bool hasEpsTransitions = false;
919  for(TransSet::Iterator tit = rRes.TransRelBegin(); tit != rRes.TransRelEnd(); ++tit) {
920  if(tit->Ev == epsEvent) {
921  hasEpsTransitions = true;
922  break;
923  }
924  }
925 
926  // Remove eps from alphabet if no eps transitions remain
927  if(!hasEpsTransitions) {
928  EventSet newAlphabet;
929  for(EventSet::Iterator evIt = rRes.AlphabetBegin(); evIt != rRes.AlphabetEnd(); ++evIt) {
930  if(*evIt != epsEvent) {
931  newAlphabet.Insert(*evIt);
932  }
933  }
934  rRes.InjectAlphabet(newAlphabet);
935  FD_DF("Removed eps from alphabet");
936  }
937 
938  // Final step: Renumber states to be consecutive 1,2,3...
939  StateSet finalStates;
940  for(StateSet::Iterator sit = rRes.StatesBegin(); sit != rRes.StatesEnd(); ++sit) {
941  finalStates.Insert(*sit);
942  }
943 
944  if(finalStates.Empty()) {
945  FD_DF("Warning: No states remaining after eps removal");
946  return;
947  }
948 
949  std::map<Idx, Idx> renumberMapping;
950  Idx newStateId = 1;
951  for(StateSet::Iterator sit = finalStates.Begin(); sit != finalStates.End(); ++sit) {
952  renumberMapping[*sit] = newStateId++;
953  }
954 
955  FD_DF("Renumbering states:");
956  for(auto& pair : renumberMapping) {
957  FD_DF(" " << pair.first << " -> " << pair.second);
958  }
959 
960  // Apply renumbering
961  RabinAutomaton tempResult;
962  tempResult.Name(rRes.Name());
963  tempResult.InjectAlphabet(rRes.Alphabet());
964 
965  // Create renumbered states
966  for(auto& pair : renumberMapping) {
967  tempResult.InsState(pair.second);
968  }
969 
970  // Renumber initial states
971  for(StateSet::Iterator sit = rRes.InitStatesBegin(); sit != rRes.InitStatesEnd(); ++sit) {
972  tempResult.SetInitState(renumberMapping[*sit]);
973  }
974 
975  // Renumber marked states
976  for(StateSet::Iterator sit = rRes.MarkedStatesBegin(); sit != rRes.MarkedStatesEnd(); ++sit) {
977  tempResult.SetMarkedState(renumberMapping[*sit]);
978  }
979 
980  // Renumber transitions
981  for(TransSet::Iterator tit = rRes.TransRelBegin(); tit != rRes.TransRelEnd(); ++tit) {
982  tempResult.SetTransition(renumberMapping[tit->X1], tit->Ev, renumberMapping[tit->X2]);
983  }
984 
985  // Renumber Rabin acceptance condition
986  RabinAcceptance originalRabin = rRes.RabinAcceptance();
987  RabinAcceptance newRabin;
988 
989  for(RabinAcceptance::Iterator rit = originalRabin.Begin(); rit != originalRabin.End(); ++rit) {
990  StateSet newR, newI;
991 
992  for(StateSet::Iterator sit = rit->RSet().Begin(); sit != rit->RSet().End(); ++sit) {
993  if(renumberMapping.find(*sit) != renumberMapping.end()) {
994  newR.Insert(renumberMapping[*sit]);
995  }
996  }
997 
998  for(StateSet::Iterator sit = rit->ISet().Begin(); sit != rit->ISet().End(); ++sit) {
999  if(renumberMapping.find(*sit) != renumberMapping.end()) {
1000  newI.Insert(renumberMapping[*sit]);
1001  }
1002  }
1003 
1004  if(!newR.Empty() && !newI.Empty()) {
1005  RabinPair newPair;
1006  newPair.RSet() = newR;
1007  newPair.ISet() = newI;
1008  newRabin.Insert(newPair);
1009  }
1010  }
1011 
1012  tempResult.RabinAcceptance() = newRabin;
1013 
1014  // Final assignment
1015  rRes = tempResult;
1016 
1017  FD_DF("RemoveEps completed using two-phase approach:");
1018  FD_DF(" Result: " << rRes.Size() << " states (renumbered 1 to " << rRes.Size() << "), "
1019  << rRes.TransRelSize() << " transitions");
1020 }
1021 
1022 } // namespace faudes
#define FD_DF(message)
Idx originalState
Original state ID.
Definition: omg_pseudodet.h:58
EnhancedState()
Default constructor.
bool operator==(const EnhancedState &other) const
Equality operator.
std::set< int > deletedNodesInPrevStep
Node numbers deleted in previous step.
Definition: omg_pseudodet.h:59
bool operator<(const EnhancedState &other) const
Comparison operator.
std::string ToString() const
Debug string representation.
virtual const char * What() const
const std::string & Name(void) const
Definition: cfl_types.cpp:422
Idx createNode()
Create a new node with auto-assigned number, return its ID.
Idx nextNodeId
Next available node ID.
std::set< int > deletedNodeNumbers
Node numbers deleted in this step.
int getNodeNumber(Idx nodeId) const
Get node number from ID.
std::map< int, Idx > numberToId
Node number -> ID mapping.
std::map< Idx, int > idToNumber
ID -> node number mapping.
Idx getNodeId(int nodeNumber) const
Get node ID from number.
Idx createNodeWithNumber(int nodeNumber)
Create a new node with specific number, return its ID.
bool hasNodeNumber(int nodeNumber) const
Check if node number exists in tree.
static const Idx INVALID_NODE
Invalid node constant.
Idx rootNode
Root node ID.
void deleteNode(Idx nodeId)
Delete a node and clean up references.
std::string ToString() const
Debug string representation.
LabeledTree()
Default constructor.
std::vector< bool > nodeNumberUsed
Track which node numbers are used.
std::map< Idx, TreeNode > nodes
Tree nodes (ID -> node)
int maxNodeCount
Maximum number of nodes (N)
bool operator==(const LabeledTree &other) const
Equality operator.
bool operator<(const LabeledTree &other) const
Comparison operator for ordering.
bool Insert(const Idx &rIndex)
StateSet & RSet(void)
Definition: omg_rabinacc.h:68
StateSet & ISet(void)
Definition: omg_rabinacc.h:84
virtual void Insert(const T &rElem)
Iterator End(void)
Iterator Begin(void)
TBaseSet< Transition, TransSort::X1EvX2 >::Iterator Iterator
Definition: cfl_transset.h:273
virtual void Clear(void)
const TaEventSet< EventAttr > & Alphabet(void) const
bool SetTransition(Idx x1, Idx ev, Idx x2)
void InjectAlphabet(const EventSet &rNewalphabet)
void RabinAcceptance(const faudes::RabinAcceptance &rRabAcc)
Definition: omg_rabinaut.h:326
TreeNode()
Default constructor.
std::string ToString() const
Debug string representation.
bool operator<(const TreeNode &other) const
Comparison operator for ordering.
bool operator==(const TreeNode &other) const
Equality operator.
std::vector< Idx > children
child nodes
Definition: omg_pseudodet.h:82
int nodeNumber
Fixed node number (1 to N)
Definition: omg_pseudodet.h:83
enum faudes::TreeNode::Color color
std::set< int > rSet
R-set (using node numbers 1..N)
Definition: omg_pseudodet.h:81
StateSet stateLabel
S: state label.
Definition: omg_pseudodet.h:79
std::set< int > aSet
A-set (using node numbers 1..N)
Definition: omg_pseudodet.h:80
std::string ToString(const std::string &rLabel="", const Type *pContext=0) const
Definition: cfl_types.cpp:175
Idx Size(void) const
StateSet::Iterator StatesBegin(void) const
StateSet::Iterator InitStatesBegin(void) const
TransSet::Iterator TransRelBegin(void) const
void ClrTransition(Idx x1, Idx ev, Idx x2)
void ClrMarkedState(Idx index)
EventSet::Iterator AlphabetBegin(void) const
bool ExistsTransition(const std::string &rX1, const std::string &rEv, const std::string &rX2) const
void SetInitState(Idx index)
StateSet::Iterator MarkedStatesBegin(void) const
bool DelState(Idx index)
StateSet::Iterator StatesEnd(void) const
void ClrInitState(Idx index)
TransSet::Iterator TransRelEnd(void) const
StateSet::Iterator MarkedStatesEnd(void) const
void SetMarkedState(Idx index)
StateSet::Iterator InitStatesEnd(void) const
Idx TransRelSize(void) const
std::string EventName(Idx index) const
EventSet::Iterator AlphabetEnd(void) const
Idx Size(void) const
bool ExistsInitState(Idx index) const
bool ExistsMarkedState(Idx index) const
bool Empty(void) const
Definition: cfl_baseset.h:1904
bool Exists(const T &rElem) const
Definition: cfl_baseset.h:2322
Iterator End(void) const
Definition: cfl_baseset.h:2098
Iterator Begin(void) const
Definition: cfl_baseset.h:2093
virtual bool Erase(const T &rElem)
Definition: cfl_baseset.h:2226
Idx Size(void) const
Definition: cfl_baseset.h:1899
void PseudoDet(const RabinAutomaton &rGen, RabinAutomaton &rRes)
std::string ComputeTreeSignature(const LabeledTree &tree, const std::set< int > &deletedNodes)
void RemoveEps(const RabinAutomaton &rGen, RabinAutomaton &rRes)
uint32_t Idx
std::string ToStringInteger(Int number)
Definition: cfl_utils.cpp:43
std::string CollapsString(const std::string &rString, unsigned int len)
Definition: cfl_utils.cpp:91

libFAUDES 2.33l --- 2025.09.16 --- c++ api documentaion by doxygen