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
10namespace faudes {
11
12/*
13********************************
14Enhanced State Implementation
15********************************
16*/
17
18EnhancedState::EnhancedState() : originalState(0) {}
19
24
29
30std::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********************************
42TreeNode Implementation
43********************************
44*/
45
46TreeNode::TreeNode() : nodeNumber(-1), color(WHITE) {}
47
48TreeNode::TreeNode(int number) : nodeNumber(number), color(WHITE) {}
49
50bool 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
59bool 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
68std::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********************************
80LabeledTree Implementation
81********************************
82*/
83
84LabeledTree::LabeledTree() : rootNode(LabeledTree::INVALID_NODE), nextNodeId(1), maxNodeCount(0) {}
85
86LabeledTree::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
150 auto it = idToNumber.find(nodeId);
151 return (it != idToNumber.end()) ? it->second : -1;
152}
153
154Idx LabeledTree::getNodeId(int nodeNumber) const {
155 auto it = numberToId.find(nodeNumber);
156 return (it != numberToId.end()) ? it->second : LabeledTree::INVALID_NODE;
157}
158
159bool LabeledTree::hasNodeNumber(int nodeNumber) const {
160 return numberToId.find(nodeNumber) != numberToId.end();
161}
162
163std::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
177bool LabeledTree::operator<(const LabeledTree& other) const {
178 if(rootNode != other.rootNode) return rootNode < other.rootNode;
180 return nodes < other.nodes;
181}
182
183bool 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********************************
199Helper Functions
200********************************
201*/
202
203std::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********************************
244Main Algorithm Implementation - PAPER COMPLIANT
245********************************
246*/
247
248void 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********************************
729RemoveEps Implementation
730********************************
731*/
732
733void 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.
EnhancedState()
Default constructor.
bool operator==(const EnhancedState &other) const
Equality operator.
std::set< int > deletedNodesInPrevStep
Node numbers deleted in previous step.
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
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)
StateSet & ISet(void)
virtual void Insert(const T &rElem)
Iterator Begin(void)
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)
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
int nodeNumber
Fixed node number (1 to N)
enum faudes::TreeNode::Color color
std::set< int > rSet
R-set (using node numbers 1..N)
StateSet stateLabel
S: state label.
std::set< int > aSet
A-set (using node numbers 1..N)
std::string ToString(const std::string &rLabel="", const Type *pContext=0) 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
bool Exists(const T &rElem) const
Iterator End(void) const
Iterator Begin(void) const
virtual bool Erase(const T &rElem)
Idx Size(void) const
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.33k --- 2025.09.16 --- c++ api documentaion by doxygen